Automatical view frustum culling (?) prevents coordinates changes in the vertex shader

Hey.
I’m trying to change the coordinates of an object in the vertex shader but the object won’t draw itself if the original object isn’t in the viewport.
For example if I set in the following scripts campPos = (0, -10, 0) and offset = vec3(0, 10, 0) then the model is properly drawn, but if I set camPos = (0, 3, 0) and offset = vec3(0, 10, 0) (so that the original cube of side 2 at (0, 0, 0) is no more in the viewport while the shifted cube should be in it) then it won’t appear.
I suspect it’d be due to an automatical view frustum culling. If so, how can I disable it ? (in the original project I was working on I have a reasonably small world so it would be okay to disable it, I think)
Thank you for your help.

scripts :

main.py

from direct.showbase.ShowBase import ShowBase, Shader
import gltf


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

        self.loadModels()
        self.initControls()
        self.loadShader()

    def initControls(self):
        self.disableMouse()
        camPos = (0, -10, 0)
        self.camera.setPos(camPos)

    def loadShader(self):
        shader = Shader.load(Shader.SL_GLSL,
                                  vertex="vertShader.vert",
                                  fragment="fragShader.frag")
        self.render.setShader(shader)

    def loadModels(self):
        gltf.patch_loader(self.loader)
        model1 = self.loader.loadModel("redCube.glb")
        model1.reparentTo(self.render)

app = MainApp()
app.run()

vertShader.vert

#version 120

uniform mat4 p3d_ModelMatrix;
uniform mat4 p3d_ViewProjectionMatrix;

attribute vec4 p3d_Vertex;

void main() {
    vec3 offset = vec3(0, 10, 0);
    vec3 worldPosition = vec3(p3d_ModelMatrix*p3d_Vertex) + offset;
    vec4 position = p3d_ViewProjectionMatrix*vec4(worldPosition, 1);
    gl_Position = position;
}

fragShader.frag

#version 120

void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

In short, the frustum culling of a given object is informed by the bounds of that object–which, as you will likely infer, is not moved with shader-driven vertices.

(This is an issue that can also occur when using Actor-animations that move their vertices significantly beyond their baseline bounds, by the way.)

One simple answer, then, is to replace these bounds. For an object that it’s always okay to render, a set of bounds that is infinitely big should do: being “infinite” in size, it’s always “in view”. In Panda, this object is called an “omni bounding volume”.

It can be used something like this:

In your importations:

from panda3d.core import OmniBoundingVolume

Elsewhere:

# Create a bounding-object
bounds = OmniBoundingVolume()
# Apply it to the affected object
self.affectedNodePath.node().setBounds(bounds)
# Inform Panda that it needn't do any further bounds-testing below this node
self.affectedNodePath.node().setFinal(True)
2 Likes

Thank you very much. It works perfectly.

(script modifications for future folks)

    def loadModels(self):
        gltf.patch_loader(self.loader)
        model1 = self.loader.loadModel("redCube.glb")
        model1.reparentTo(self.render)
        bounds = OmniBoundingVolume()
        model1.node().setBounds(bounds)
        model1.node().setFinal(True)
1 Like