Shader generator: shaders disabling

In a current project of mine I have a simple split-screen interface (taken from code found here on the forum, as I recall), and the shader generator on. To the best of my knowledge the generator is producing only two effects: per-pixel lighting and glow.

Alas, I’m finding that under certain circumstances, which seem to be related to position and/or orientation, the shader generator seems to “turn off” in on of the views, with both the per-pixel lighting and the glow disappearing.

While the other view doesn’t seem to be affected, this may simply be because I am currently not moving its camera around.

The following images should hopefully illustrate, taken, as I recall, from the same run and with the only known change between the two states being a small rotation (and some time, of course):

My thanks for any help.

This rather sounds like the sort of bug that creeps into low-level Panda from time to time: if the full state doesn’t get managed properly, some state attributes can appear to flicker on and off as the camera changes viewing angles.

Can you put together a smallish app that demonstrates this problem?

David

Thank you very much - I’ll hopefully get one ready tomorrow (I seem to be a little out of it tonight, and seem to be having trouble with all sorts of silly mistakes as I try to get the mini version to work >_<).

All right, the following (somewhat hacky, I think) code seems to more-or-less work.

I’m honestly not sure that it’s showing quite the same problem, as mine seems to have some component of position and/or orientation, in at least some tests, whereas this seems to simply have it working in one view and not doing so in the other. Nevertheless, there does seem to be something unexpected going on in this code, and hopefully it’s the problem that I’m having… ^^;

Perhaps of note is that the order of display region creation seems to matter: switching the order seems to result in the issue swapping views.

I also suspect that glows and perhaps normals are involved (hence my use of the Tron model, as I recall); I don’t think that I managed to get it to work with the standing panda, but it seems to do so with the Tron model. Note that my own model has both normals and glow, and a total of three separate .png images (colour, glow and normal map), as I recall.

There are probably a number of unused imports in this, since I didn’t remove any, I don’t think.

import random

import direct.directbase.DirectStart
from pandac.PandaModules import *

from direct.task import Task
from direct.actor import Actor
import math
import sys

from direct.showbase.DirectObject import DirectObject
from direct.showbase import Audio3DManager
from direct.gui.DirectGui import *
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import CardMaker

MAX_ROTATION = 12000.0

class World(DirectObject):
    def __init__(self):
        """World initialisation.  Deals with various startup matters"""
        random.seed()
        
        props = WindowProperties()
        props.setCursorHidden(True)
        base.win.requestProperties(props)
        
        self.aspect_ratio = base.getAspectRatio()
        
        base.setBackgroundColor(0, 0, 0)

        render.setShaderAuto()
        
        ambient = AmbientLight("ambient")
        ambient.setColor(VBase4(0.2, 0.17, 0.15, 1.0))
        ambient_node = render.attachNewNode(ambient)
        render.setLight(ambient_node)
        main_light = DirectionalLight("main")
        main_light.setColor(VBase4(0.4, 0.7, 0.8, 1.0))
        main_light.setSpecularColor(VBase4(0, 0, 0, 1.0))
        main_light_node = render.attachNewNode(main_light)
        main_light_node.setHpr(155, -50, 0)
        render.setLight(main_light_node)
        
        base.disableMouse()
       
        self.holder1 = render.attachNewNode(PandaNode("holder 1"))
        self.holder2 = render.attachNewNode(PandaNode("holder 2"))
        
        self.player1 = loader.loadModel("samples/Glow-Filter/models/tron")
        self.player1.reparentTo(self.holder1)
        self.player1.setScale(0.2)
        self.player1.setH(180)
        
        self.player2 = loader.loadModel("samples/Glow-Filter/models/tron")
        self.player2.reparentTo(self.holder2)
        self.player2.setScale(0.2)
        self.player2.setH(180)
                
        defaultCamDisplay = base.camNode.getDisplayRegion(0)
        defaultCamDisplay.setActive(0)
        
        p1Camera = Camera("player 1 camera")
        p2Camera = Camera("player 2 camera")
        
        p1CameraNP = self.holder1.attachNewNode(p1Camera)
        p1CameraNP.setY(-7.0)
        p1CameraNP.setZ(2.0)
        p1Camera.getLens().setAspectRatio(p1Camera.getLens().getAspectRatio()*2.0)
        
        p2CameraNP = self.holder2.attachNewNode(p2Camera)
        p2CameraNP.setY(-7.0)
        p2CameraNP.setZ(2.0)
        p2Camera.getLens().setAspectRatio(p2Camera.getLens().getAspectRatio()*2.0)
        
        window = defaultCamDisplay.getWindow()
        #p2Display = window.makeDisplayRegion(0.0, 1.0, 0.5, 1.0)
        p1Display = window.makeDisplayRegion(0.0, 1.0, 0.0, 0.5)
        p2Display = window.makeDisplayRegion(0.0, 1.0, 0.5, 1.0)
        
        p1Display.setCamera(p1CameraNP)
        p2Display.setCamera(p2CameraNP)
        
        self.last_mouse = Vec3(0, 0, 0)
        
        self.keys = {"up":False, "down":False, "left":False, "right":False,
                     "action1":False, "action2":False, "action3":False,
                     "space":False, "edit":False}
        
        self.accept("escape", sys.exit)
        
        self.accept("w", self.setKey, ["up", True])
        self.accept("w-up", self.setKey, ["up", False])
        self.accept("s", self.setKey, ["down", True])
        self.accept("s-up", self.setKey, ["down", False])
        self.accept("a", self.setKey, ["left", True])
        self.accept("a-up", self.setKey, ["left", False])
        self.accept("d", self.setKey, ["right", True])
        self.accept("d-up", self.setKey, ["right", False])
        self.accept("mouse1", self.setKey, ["action1", True])
        self.accept("mouse1-up", self.setKey, ["action1", False])
        self.accept("mouse3", self.setKey, ["action2", True])
        self.accept("mouse3-up", self.setKey, ["action2", False])
        self.accept("space", self.setKey, ["space", True])
        self.accept("space-up", self.setKey, ["space", False])
        self.accept("e", self.setKey, ["edit", True])
        self.accept("e-up", self.setKey, ["edit", False])
        
        self.update_task = taskMgr.add(self.update, "update")
        self.update_task.last_time = 0
        
    def update(self, task):
        """Game update loop."""
        dt = task.time - task.last_time
        task.last_time = task.time
        
        mouse_x = 0
        mouse_y = 0
        if base.mouseWatcherNode.hasMouse():
            mouse_x = base.mouseWatcherNode.getMouseX()
            mouse_y = base.mouseWatcherNode.getMouseY()
            self.holder1.setH(self.holder1.getH() -mouse_x*MAX_ROTATION*dt)
            if base.win.hasSize():
                base.win.movePointer(0, base.win.getXSize()/2, base.win.getYSize()/2)

        p1Moving = False
        if self.keys["up"]:
            p1Moving = True
                            
        if p1Moving:
            forward = self.holder1.getQuat().getForward()
            forward.normalize()
            self.holder1.setPos(self.holder1.getPos() + forward*10.0*dt)
        self.holder1.setZ(1)
        self.holder2.setZ(1)
        
        return Task.cont
    
    def setKey(self, key, state):
        self.keys[key] = state
    
world = World()
run()