Stencil Shadows HELP

Could someone please - please help me get treeform stencil shadow into my game. I have been trying for months, and I am not getting it worked out.

Here is what I have.
For starting:

from pandac.PandaModules import *
import sys,os
loadPrcFileData("", "prefer-parasite-buffer 

#f")
loadPrcFileData("",""" 
framebuffer-stencil #t 
stencil-bits 8 
""") 

import direct.directbase.DirectStart 
from direct.showbase import *
from direct.gui.DirectGui import *

This is the shadow code:

def ShadowSystem(shadowColor = Vec4(0,0,0,.3)):    
    """ creates an overlay screen which is drawn last which is our shadow""" 
    screen = StencilAttrib.make( 
         1, 
         StencilAttrib.SCFNotEqual, 
         StencilAttrib.SOKeep, 
         StencilAttrib.SOKeep, 
         StencilAttrib.SOKeep, 
         0, 
         0xFFFFFFFF, 
         0xFFFFFFFF) 
    cm = CardMaker("screener") 
    cm.setFrame(-1,1,-1,1) 
    node =render2d.attachNewNode( cm.generate()) 
    node.setAttrib(screen) 
    node.setColor(shadowColor) 
    node.setTransparency(True) 
    node.setBin("unsorted",0) 
    

class Connectivity: 
    """ connectivity class which will be useful for many algorithms """ 
    
    class Face: 
        """ logic face """ 
        vertexes = [] 
        plane = None 
        edges = [] 
        neighbours = [] 
        visible = True 
        
    class Plane: 
        """ plane equation """ 
        a = 0 
        b = 0 
        c = 0 
        d = 0 
    
    def __init__(self,object):        
        """ creates connectivity per objects basis """        
        self.object = object 
        self.faces = [] 
        self.process() 
        self.computeConnectivity() 
          
    def computeConnectivityOnFaceList(self,faceList): 
        """ computes conectivity """ 
        # for every face in the list see if there is an edge 
        # that matches on another face, then they are neighbours 
        for faceA in faceList:              
            for e1,edge1 in enumerate(faceA.edges): 
                if faceA.neighbours[e1] == None: 
                    for faceB in faceList: 
                        if faceB != faceA: 
                            next = False 
                            for e2,edge2 in enumerate(faceB.edges): 
                                if edge1[0] == edge2[0] and edge1[1] == edge2[1]: 
                                    faceA.neighbours[e1] = faceB 
                                    faceB.neighbours[e2] = faceA 
                                    next = True 
                                    break 
                                elif edge1[1] == edge2[0] and edge1[0] == edge2[1]: 
                                    faceA.neighbours[e1] = faceB 
                                    faceB.neighbours[e2] = faceA 
                                    next = True 
                                    break 
                            if next: break 
            
    def computeConnectivity(self): 
        """ now and little more compiles one """ 
        i = 0 
        mach = {} 
        # puts every vertex into a mach tabe inside a 
        # list with faces that share that vertex 
        for face in self.faces:  
            for vertex in face.vertexes: 
                vd =  int(vertex[0]*1000),int(vertex[1]*1000),int(vertex[2]*1000) 
                if vd in mach: 
                    mach[vd].append(face) 
                else: 
                    mach[vd] = [face] 
        # now look through the list and see if any face matches    
        for matches in mach.itervalues(): 
            if len(matches) > 1: 
                self.computeConnectivityOnFaceList(matches) 
          
    def process(self): 
        self.faces = [] 
        geomNodeCollection = self.object.findAllMatches('**/+GeomNode') 
        for nodePath in geomNodeCollection.asList(): 
            geomNode = nodePath.node() 
            self.processGeomNode(geomNode) 
          
          
    def processGeomNode(self,geomNode):        
        for i in range(geomNode.getNumGeoms()): 
            geom = geomNode.getGeom(i) 
            state = geomNode.getGeomState(i) 
            self.processGeom(geom) 
                
    def processGeom(self,geom): 
        vdata = geom.getVertexData() 
        for i in range(geom.getNumPrimitives()): 
            prim = geom.getPrimitive(i) 
            self.processPrimitive(prim, vdata)  
            
    def processPrimitive(self,prim, vdata): 
        vertex = GeomVertexReader(vdata, 'vertex') 
        prim = prim.decompose() 
        for p in range(prim.getNumPrimitives()): 
            s = prim.getPrimitiveStart(p) 
            e = prim.getPrimitiveEnd(p) 
            vertexes = [] 
            for i in range(s, e): 
                vi = prim.getVertex(i) 
                vertex.setRow(vi) 
                v = vertex.getData3f() 
                vertexes.append(v) 
            face = self.Face() 
            face.vertexes = vertexes 
            face.plane = self.Plane() 
            face.plane.a = vertexes[0][1]*(vertexes[1][2]-vertexes[2][2]) + vertexes[1][1]*(vertexes[2][2]-vertexes[0][2]) + vertexes[2][1]*(vertexes[0][2]-vertexes[1][2]); 
            face.plane.b = vertexes[0][2]*(vertexes[1][0]-vertexes[2][0]) + vertexes[1][2]*(vertexes[2][0]-vertexes[0][0]) + vertexes[2][2]*(vertexes[0][0]-vertexes[1][0]); 
            face.plane.c = vertexes[0][0]*(vertexes[1][1]-vertexes[2][1]) + vertexes[1][0]*(vertexes[2][1]-vertexes[0][1]) + vertexes[2][0]*(vertexes[0][1]-vertexes[1][1]); 
            face.plane.d = -( vertexes[0][0]*( vertexes[1][1]*vertexes[2][2] - vertexes[2][1]*vertexes[1][2] ) + 
                vertexes[1][0]*(vertexes[2][1]*vertexes[0][2] - vertexes[0][1]*vertexes[2][2]) + 
                vertexes[2][0]*(vertexes[0][1]*vertexes[1][2] - vertexes[1][1]*vertexes[0][2]) ); 
            face.edges = [(vertexes[0],vertexes[1]),(vertexes[1],vertexes[2]),(vertexes[2],vertexes[0])] 
            face.neighbours = [None,None,None] 
            self.faces.append(face) 

class Shadow: 
    """ main class of the shadow """ 
    
    frontSide = StencilAttrib.make( 
                1, 
                StencilAttrib.SCFAlways, 
                StencilAttrib.SOKeep, 
                StencilAttrib.SOKeep, 
                StencilAttrib.SOIncrement, 
                0xFFFFFFFF, 
                0xFFFFFFFF, 
                0xFFFFFFFF) 

    backSide = StencilAttrib.make( 
                1, 
                StencilAttrib.SCFAlways, 
                StencilAttrib.SOKeep, 
                StencilAttrib.SOKeep, 
                StencilAttrib.SODecrement, 
                0xFFFFFFFF, 
                0xFFFFFFFF, 
                0xFFFFFFFF) 

    def __init__(self,object,light): 
        """ connect the object with the light """ 
        self.object = object 
        self.light = light 
        self.con = Connectivity(object) 
        self.faces = self.con.faces 
                  
    def lightFaces(self): 
        """ runs through all the faces and see if they are lit """ 
        l = self.light.getPos(self.object) 
        for face in self.faces: 
            side = (face.plane.a*l[0]+ 
                face.plane.b*l[1]+ 
                face.plane.c*l[2]+ 
                face.plane.d) 
            print side 
            if side > 0 : 
                face.visible = True 
            else: 
                face.visible = False 
                  
    def generate(self): 
        """ generate a shadow volume based on the light and the object """ 
        self.lightFaces() 
        l = self.light.getPos(self.object) 
        vdata = GeomVertexData('shadow', GeomVertexFormat.getV3() , Geom.UHStatic) 
        vertex = GeomVertexWriter(vdata, 'vertex') 
        number = 0 
        for face in  self.faces: 
            if face.visible: 
                for e,edge in enumerate(face.edges): 
                    if face.neighbours[e] == None or not face.neighbours[e].visible: 
                        v1 = edge[0] 
                        v2 = v1+(v1-l)*10 
                        v3 = edge[1] 
                        v4 = v3+(v3-l)*10 
                        vertex.addData3f(v1) 
                        vertex.addData3f(v2) 
                        vertex.addData3f(v3) 
                        vertex.addData3f(v3) 
                        vertex.addData3f(v2) 
                        vertex.addData3f(v4) 
                        number = number + 2 
        prim = GeomTriangles(Geom.UHStatic) 
        for n in range(number): 
            prim.addVertices(n*3,n*3+1,n*3+2) 
        prim.closePrimitive() 
        geom = Geom(vdata) 
        geom.addPrimitive(prim) 
        geomnode = GeomNode('gnode') 
        geomnode.addGeom(geom) 
        # make the 1st pass        
        self.front = NodePath("front") 
        self.front.attachNewNode(geomnode) 
        self.front.setColor(0,0,0,.1) 
        self.front.setAttrib( ColorWriteAttrib.make(ColorWriteAttrib.MOff) ) 
        self.front.setAttrib( CullFaceAttrib.make() ) 
        self.front.setAttrib( DepthWriteAttrib.make(DepthWriteAttrib.MOff ) ) 
        self.front.setAttrib( self.frontSide ) 
        self.front.reparentTo(self.object) 
        self.front.setBin("fixed",1) 
        # make the second pass 
        self.back = NodePath("back") 
        self.back.attachNewNode(geomnode) 
        self.back.setColor(0,0,0,.1) 
        self.back.setAttrib( ColorWriteAttrib.make(ColorWriteAttrib.MOff) ) 
        self.back.setAttrib( CullFaceAttrib.makeReverse() ) 
        self.back.setAttrib( DepthWriteAttrib.make(DepthWriteAttrib.MOff ) ) 
        self.back.setAttrib( self.backSide ) 
        self.back.reparentTo(self.object) 
        self.back.setBin("fixed",2) 
        return NodePath("shadow of %s"%object) 


if __name__ == "__main__": 
    ## # creae fore 
    ## cm = CardMaker("back") 
    ## cm.setFrame(10,-10,-10,10) 
    ## cmNode = render.attachNewNode(cm.generate()) 
    ## cmNode.setR(180) 
    # load object 
    object = loader.loadModelCopy('Models/ball')  
    object.reparentTo(render) 
    object.setPos(0,0,10) 
    object.setScale(1,1,1) 
    ## object.setP(-90)      
    base.cam.setPos(10,10,25) 
    base.cam.lookAt(Point3(0,0,0),Vec3(0,1,0))    
    # set up shadow system 
    ShadowSystem() 
    # create light 
    light = NodePath("light") 
    light.setPos(5,15,15) 
    # attach shadow to object and light 
    sh = Shadow(object,light) 
    # generate a shadow object 
    shnode = sh.generate() 
    # reparent it to the frame 
    shnode.reparentTo(render)  

…and this is my world:

class World(DirectObject.DirectObject): 

    def __init__( self ): 

        #########################################################
        """SETUP"""
        #########################################################
        # View Framerate
        self.fps = base.setFrameRateMeter(1)
        """VARIABLES"""
        self.page = 0
        
        self.activate()
        
    # This Function Starts the Game
    def activate(self):
        self.page = 1
        # SCENE
        self.env = loader.loadModel("Models/world") 
        self.env.reparentTo(render) 
        self.env.setPos(0,0,0)

        """KEY INPUT"""
        self.accept("escape", self.endGame)
        
        # start button
        self.playEgg = loader.loadModel("Models/play_buttons.egg")
        self.playButton = DirectButton(scale = 0.2, pos=(0, 0, -0.95), relief = None, rolloverSound = None, command = self.startPlay,
                                    geom = (self.playEgg.find("**/play_def"), self.playEgg.find("**/play_glow"), self.playEgg.find("**/play_glow"), self.playEgg.find("**/play_def")))
        self.playButton.setTransparency(1)
        self.playButton.setColor(0.9,0.95,0.7,1)
  
    """Commence Game"""
    def startPlay(self):
        self.playButton.hide()
    
    """Game End"""
    def endGame(self):
        sys.exit()

…and then I run:

world = World( ) 
run( )

You see the stuff in after “if name == “main”:” You need to stick this some place into world’s init method. But giving the shadow system proper parameters for your objects and lights.

Yes, I tried that. What’s beating me is ‘object’. I don’t know how to manage the line 'self.object = object '. I keep getting problems when I change ‘object’ to self.something. Can you show me an example please?

example of what? Object is just a name you have to load a model you want to cast shadows and then generate them.

Ok thanks. I made some headway. I’ll keep at it.

I am a bit slow, but I hope you will be patient with me.
I know what the object does, but I have been trying for hours to figure out how to get other objects to do the same. I am sure I am supposed to link my other objects to this object somehow, so that they can cast shadow too, but I feel like I am at rock bottom. I just need someone to simply show me how? The bold part of my code is all I want to be affected. Someone please help.

from pandac.PandaModules import *
import sys,os
loadPrcFileData("", “prefer-parasite-buffer #f”)
loadPrcFileData("","""
framebuffer-stencil #t
stencil-bits 8
“”")

import direct.directbase.DirectStart
from direct.showbase import *
from direct.gui.DirectGui import *

def ShadowSystem(shadowColor = Vec4(0,0,0,.3)):
“”" creates an overlay screen which is drawn last which is our shadow"""
screen = StencilAttrib.make(
1,
StencilAttrib.SCFNotEqual,
StencilAttrib.SOKeep,
StencilAttrib.SOKeep,
StencilAttrib.SOKeep,
0,
0xFFFFFFFF,
0xFFFFFFFF)
cm = CardMaker(“screener”)
cm.setFrame(-1,1,-1,1)
node =render2d.attachNewNode( cm.generate())
node.setAttrib(screen)
node.setColor(shadowColor)
node.setTransparency(True)
node.setBin(“unsorted”,0)

class Connectivity:
“”" connectivity class which will be useful for many algorithms “”"

class Face: 
    """ logic face """ 
    vertexes = [] 
    plane = None 
    edges = [] 
    neighbours = [] 
    visible = True 
    
class Plane: 
    """ plane equation """ 
    a = 0 
    b = 0 
    c = 0 
    d = 0 

def __init__(self,object):        
    """ creates connectivity per objects basis """        
    self.object = object 
    self.faces = [] 
    self.process() 
    self.computeConnectivity() 
      
def computeConnectivityOnFaceList(self,faceList): 
    """ computes conectivity """ 
    # for every face in the list see if there is an edge 
    # that matches on another face, then they are neighbours 
    for faceA in faceList:              
        for e1,edge1 in enumerate(faceA.edges): 
            if faceA.neighbours[e1] == None: 
                for faceB in faceList: 
                    if faceB != faceA: 
                        next = False 
                        for e2,edge2 in enumerate(faceB.edges): 
                            if edge1[0] == edge2[0] and edge1[1] == edge2[1]: 
                                faceA.neighbours[e1] = faceB 
                                faceB.neighbours[e2] = faceA 
                                next = True 
                                break 
                            elif edge1[1] == edge2[0] and edge1[0] == edge2[1]: 
                                faceA.neighbours[e1] = faceB 
                                faceB.neighbours[e2] = faceA 
                                next = True 
                                break 
                        if next: break 
        
def computeConnectivity(self): 
    """ now and little more compiles one """ 
    i = 0 
    mach = {} 
    # puts every vertex into a mach tabe inside a 
    # list with faces that share that vertex 
    for face in self.faces:  
        for vertex in face.vertexes: 
            vd =  int(vertex[0]*1000),int(vertex[1]*1000),int(vertex[2]*1000) 
            if vd in mach: 
                mach[vd].append(face) 
            else: 
                mach[vd] = [face] 
    # now look through the list and see if any face matches    
    for matches in mach.itervalues(): 
        if len(matches) > 1: 
            self.computeConnectivityOnFaceList(matches) 
      
def process(self): 
    self.faces = [] 
    geomNodeCollection = self.object.findAllMatches('**/+GeomNode') 
    for nodePath in geomNodeCollection.asList(): 
        geomNode = nodePath.node() 
        self.processGeomNode(geomNode) 
      
      
def processGeomNode(self,geomNode):        
    for i in range(geomNode.getNumGeoms()): 
        geom = geomNode.getGeom(i) 
        state = geomNode.getGeomState(i) 
        self.processGeom(geom) 
            
def processGeom(self,geom): 
    vdata = geom.getVertexData() 
    for i in range(geom.getNumPrimitives()): 
        prim = geom.getPrimitive(i) 
        self.processPrimitive(prim, vdata)  
        
def processPrimitive(self,prim, vdata): 
    vertex = GeomVertexReader(vdata, 'vertex') 
    prim = prim.decompose() 
    for p in range(prim.getNumPrimitives()): 
        s = prim.getPrimitiveStart(p) 
        e = prim.getPrimitiveEnd(p) 
        vertexes = [] 
        for i in range(s, e): 
            vi = prim.getVertex(i) 
            vertex.setRow(vi) 
            v = vertex.getData3f() 
            vertexes.append(v) 
        face = self.Face() 
        face.vertexes = vertexes 
        face.plane = self.Plane() 
        face.plane.a = vertexes[0][1]*(vertexes[1][2]-vertexes[2][2]) + vertexes[1][1]*(vertexes[2][2]-vertexes[0][2]) + vertexes[2][1]*(vertexes[0][2]-vertexes[1][2]); 
        face.plane.b = vertexes[0][2]*(vertexes[1][0]-vertexes[2][0]) + vertexes[1][2]*(vertexes[2][0]-vertexes[0][0]) + vertexes[2][2]*(vertexes[0][0]-vertexes[1][0]); 
        face.plane.c = vertexes[0][0]*(vertexes[1][1]-vertexes[2][1]) + vertexes[1][0]*(vertexes[2][1]-vertexes[0][1]) + vertexes[2][0]*(vertexes[0][1]-vertexes[1][1]); 
        face.plane.d = -( vertexes[0][0]*( vertexes[1][1]*vertexes[2][2] - vertexes[2][1]*vertexes[1][2] ) + 
            vertexes[1][0]*(vertexes[2][1]*vertexes[0][2] - vertexes[0][1]*vertexes[2][2]) + 
            vertexes[2][0]*(vertexes[0][1]*vertexes[1][2] - vertexes[1][1]*vertexes[0][2]) ); 
        face.edges = [(vertexes[0],vertexes[1]),(vertexes[1],vertexes[2]),(vertexes[2],vertexes[0])] 
        face.neighbours = [None,None,None] 
        self.faces.append(face) 

class Shadow:
“”" main class of the shadow “”"

frontSide = StencilAttrib.make( 
            1, 
            StencilAttrib.SCFAlways, 
            StencilAttrib.SOKeep, 
            StencilAttrib.SOKeep, 
            StencilAttrib.SOIncrement, 
            0xFFFFFFFF, 
            0xFFFFFFFF, 
            0xFFFFFFFF) 

backSide = StencilAttrib.make( 
            1, 
            StencilAttrib.SCFAlways, 
            StencilAttrib.SOKeep, 
            StencilAttrib.SOKeep, 
            StencilAttrib.SODecrement, 
            0xFFFFFFFF, 
            0xFFFFFFFF, 
            0xFFFFFFFF) 

def __init__(self,object,light): 
    """ connect the object with the light """ 
    self.object = object 
    self.light = light 
    self.con = Connectivity(object) 
    self.faces = self.con.faces 
              
def lightFaces(self): 
    """ runs through all the faces and see if they are lit """ 
    l = self.light.getPos(self.object) 
    for face in self.faces: 
        side = (face.plane.a*l[0]+ 
            face.plane.b*l[1]+ 
            face.plane.c*l[2]+ 
            face.plane.d) 
        print side 
        if side > 0 : 
            face.visible = True 
        else: 
            face.visible = False 
              
def generate(self): 
    """ generate a shadow volume based on the light and the object """ 
    self.lightFaces() 
    l = self.light.getPos(self.object) 
    vdata = GeomVertexData('shadow', GeomVertexFormat.getV3() , Geom.UHStatic) 
    vertex = GeomVertexWriter(vdata, 'vertex') 
    number = 0 
    for face in  self.faces: 
        if face.visible: 
            for e,edge in enumerate(face.edges): 
                if face.neighbours[e] == None or not face.neighbours[e].visible: 
                    v1 = edge[0] 
                    v2 = v1+(v1-l)*10 
                    v3 = edge[1] 
                    v4 = v3+(v3-l)*10 
                    vertex.addData3f(v1) 
                    vertex.addData3f(v2) 
                    vertex.addData3f(v3) 
                    vertex.addData3f(v3) 
                    vertex.addData3f(v2) 
                    vertex.addData3f(v4) 
                    number = number + 2 
    prim = GeomTriangles(Geom.UHStatic) 
    for n in range(number): 
        prim.addVertices(n*3,n*3+1,n*3+2) 
    prim.closePrimitive() 
    geom = Geom(vdata) 
    geom.addPrimitive(prim) 
    geomnode = GeomNode('gnode') 
    geomnode.addGeom(geom) 
    # make the 1st pass        
    self.front = NodePath("front") 
    self.front.attachNewNode(geomnode) 
    self.front.setColor(0,0,0,.1) 
    self.front.setAttrib( ColorWriteAttrib.make(ColorWriteAttrib.MOff) ) 
    self.front.setAttrib( CullFaceAttrib.make() ) 
    self.front.setAttrib( DepthWriteAttrib.make(DepthWriteAttrib.MOff ) ) 
    self.front.setAttrib( self.frontSide ) 
    self.front.reparentTo(self.object) 
    self.front.setBin("fixed",1) 
    # make the second pass 
    self.back = NodePath("back") 
    self.back.attachNewNode(geomnode) 
    self.back.setColor(0,0,0,.1) 
    self.back.setAttrib( ColorWriteAttrib.make(ColorWriteAttrib.MOff) ) 
    self.back.setAttrib( CullFaceAttrib.makeReverse() ) 
    self.back.setAttrib( DepthWriteAttrib.make(DepthWriteAttrib.MOff ) ) 
    self.back.setAttrib( self.backSide ) 
    self.back.reparentTo(self.object) 
    self.back.setBin("fixed",2) 
    return NodePath("shadow of %s"%object) 

class World(DirectObject.DirectObject):

def __init__( self ): 
    
    self.dummyNode = render.attachNewNode("renderMulti")
    # load object 
    object = loader.loadModelCopy('Models/frog_rock01')  
    object.reparentTo(render) 
    object.setPos(0,0,5) 
    object.setScale(1,1,1) 
    ## object.setP(-90)      
    base.cam.setPos(10,10,75) 
    base.cam.lookAt(Point3(0,0,0),Vec3(0,1,0))    
    [b]# test object
    self.rock = loader.loadModel("Models/frog_rock02")
    self.rock.setPos(-20,10,5)
    self.rock.setScale(1)
    self.rock.reparentTo(object) [/b]
    # set up shadow system 
    ShadowSystem() 
    # create light 
    light = NodePath("light") 
    light.setPos(75,55,100) 
    # attach shadow to object and light 
    sh = Shadow(object,light) 
    # generate a shadow object 
    shnode = sh.generate() 
    # reparent it to the frame 
    shnode.reparentTo(render) 
    
    #########################################################
    """SETUP"""
    #########################################################
    # View Framerate
    self.fps = base.setFrameRateMeter(1)
    """VARIABLES"""
    self.page = 0
    
    self.activate()
    
# This Function Starts the Game
def activate(self):
    self.page = 1
    # SCENE
    self.env = loader.loadModel("Models/world") 
    self.env.reparentTo(render) 
    self.env.setPos(0,0,0)

    """KEY INPUT"""
    self.accept("escape", self.endGame)
    
    # start button
    self.playEgg = loader.loadModel("Models/play_buttons.egg")
    self.playButton = DirectButton(scale = 0.2, pos=(0, 0, -0.95), relief = None, rolloverSound = None, command = self.startPlay,
                                geom = (self.playEgg.find("**/play_def"), self.playEgg.find("**/play_glow"), self.playEgg.find("**/play_glow"), self.playEgg.find("**/play_def")))
    self.playButton.setTransparency(1)
    self.playButton.setColor(0.9,0.95,0.7,1)

"""Commence Game"""
def startPlay(self):
    self.playButton.hide()

"""Game End"""
def endGame(self):
    sys.exit()

world = World( )
run( )

make the object = NodePath(“shadow root node”)
then reparent things you want to be shadowed to this?

OK

object = NodePath(“shadow root node”)

self.rock.reparentTo(object)

That didn’t work. Both objects disappeared. What do I do now?