Shadows not rendering correctly when setShaderAuto() is used

from direct.showbase.ShowBase import ShowBase
from panda3d.core import *

class Core(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.cam.setPos(-5,-5,7)
        self.cam.setHpr(315,-40,0)

        render.setShaderAuto()

        sun = Spotlight('sun')
        self.sun = render.attachNewNode(sun)
        sun.setScene(render)
        sun.setShadowCaster(True)
        self.sun.setHpr(-20,-45,0)
        self.sun.setPos(-5,-20,30)
        sun.setColorTemperature(4500)
        render.setLight(self.sun)

        cube1 = self.makeCube('cube1', 1, 1, 1, 0, 0, 0)

    def makeSquare(self, x1, y1, z1, x2, y2, z2):
        format = GeomVertexFormat.getV3n3cpt2()
        vdata = GeomVertexData('square', format, Geom.UHDynamic)

        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')
        color = GeomVertexWriter(vdata, 'color')
        texcoord = GeomVertexWriter(vdata, 'texcoord')

        if x1 != x2:
            vertex.addData3f(x1, y1, z1)
            vertex.addData3f(x2, y1, z1)
            vertex.addData3f(x2, y2, z2)
            vertex.addData3f(x1, y2, z2)

            normal.addData3f(Vec3(2 * x1 - 1, 2 * y1 - 1, 2 * z1 - 1))
            normal.addData3f(Vec3(2 * x2 - 1, 2 * y1 - 1, 2 * z1 - 1))
            normal.addData3f(Vec3(2 * x2 - 1, 2 * y2 - 1, 2 * z2 - 1))
            normal.addData3f(Vec3(2 * x1 - 1, 2 * y2 - 1, 2 * z2 - 1))

        else:
            vertex.addData3f(x1, y1, z1)
            vertex.addData3f(x2, y2, z1)
            vertex.addData3f(x2, y2, z2)
            vertex.addData3f(x1, y1, z2)

            normal.addData3f(Vec3(2 * x1 - 1, 2 * y1 - 1, 2 * z1 - 1))
            normal.addData3f(Vec3(2 * x2 - 1, 2 * y2 - 1, 2 * z1 - 1))
            normal.addData3f(Vec3(2 * x2 - 1, 2 * y2 - 1, 2 * z2 - 1))
            normal.addData3f(Vec3(2 * x1 - 1, 2 * y1 - 1, 2 * z2 - 1))

        color.addData4f(1.0, 1.0, 1.0, 1.0)

        texcoord.addData2f(0.0, 1.0)
        texcoord.addData2f(0.0, 0.0)
        texcoord.addData2f(1.0, 0.0)
        texcoord.addData2f(1.0, 1.0)

        tri1 = GeomTriangles(Geom.UHDynamic)
        tri2 = GeomTriangles(Geom.UHDynamic)

        tri1.addVertex(0)
        tri1.addVertex(1)
        tri1.addVertex(3)

        tri2.addConsecutiveVertices(1, 3)

        tri1.closePrimitive()
        tri2.closePrimitive()

        square = Geom(vdata)
        square.addPrimitive(tri1)
        square.addPrimitive(tri2)

        return square

    def makeCube(self,name, length, width, height, x, y, z):
        main1pt = [x, y, z]
        main1pt1 = [x + length, y, z + height]
        main1pt2 = [x, y + width, z + height]
        main1pt3 = [x + length, y + width, z]

        main2pt = [x + length, y + width, z + height]
        main2pt1 = [x, y + width, z]
        main2pt2 = [x + length, y, z]
        main2pt3 = [x, y, z + height]

        square0 = self.makeSquare(*(main1pt + main1pt1))
        square1 = self.makeSquare(*(main1pt + main1pt2))
        square2 = self.makeSquare(*(main1pt + main1pt3))
        square3 = self.makeSquare(*(main2pt + main2pt1))
        square4 = self.makeSquare(*(main2pt + main2pt2))
        square5 = self.makeSquare(*(main2pt + main2pt3))

        snode = GeomNode(name)
        snode.addGeom(square0)
        snode.addGeom(square1)
        snode.addGeom(square2)
        snode.addGeom(square3)
        snode.addGeom(square4)
        snode.addGeom(square5)
        cube = render.attachNewNode(snode)
        cube.setTwoSided(True)
        return cube

core = Core()
core.run()

Lighting works fine without setShaderAuto() but when I call it, shadows become really weird. Tried adding a texture to the cube and same issue.

This is a known issue.

I see, I didn’t really understand the diagnosis of the issue. Is there a solution to this or should I just not call render.setShaderAuto() and wait for the fix in 1.11?

edit: Changing my Spotlight() to SphereLight() seems to fix the weird shadow mapping on the cube itself but the cube’s shadow on the ground is not not rendering.

edit: All lights seem to behave the same as SphereLight() while only Spotlight() has the initial issue

I do not know the solution for this. But as an option, you can use your own shaders.

Can you recommend any existing shaders? Nothing fancy

Example:

Thank you, shadows mostly work fine

I don’t think this is the same issue as the one linked to by @serega-kkz. This seems to be a more simple form of shadow acne. One major issue is that the cube is two-sided, and the back polygons shadow on the front ones. If you comment out setTwoSided, you’ll see that the acne goes away. You’ll just have to also close the cube properly with the right winding orders.

Note that the default near/far distances for the light are also too wide. Currently, the frustum is massive compared to the model, which will not help shadow quality, just enable self.sun.node().showFrustum() and you’ll see the frustum; call self.sun.node().getLens().setNearFar(30, 40) for something more reasonable in this situation.

Finally, you can call render.setDepthOffset(-2) to apply a bias to the rendering, which would obviate the need to disable two-sided rendering.

1 Like

That seemed to have fixed all the mentioned issues and now shadows work perfectly :smiley: Thank you!