Distance Rendering

Everything goes gray when I move away from center of map

Created a grid using lines and a bounding box,
The Idea was to have 8K world map, so 8000 units by 4000 units.

When I leave the center at some distance the screen just goes
completely grey. My background was set to black, but that goes grey too.

self.camLens.setFar(100000)

so my question dear friends, why?
is panda3D world limited to a small area around 0, 0, 0?
do we have to re-render every few thousand units.

Some Screenshot and references:

Here is the overview of SHENKO world map,
9 nodes, 9 different sectors, 4k being the center surrounded by 1080p areas

Here is a screenshot of what I have so far.

Suggestions from AI:

Original script:

I use a PS5 remote as my input device,


#!/usr/bin/env python3

"""
Drawing a 8K world map
"""

from panda3d.core import AmbientLight
from panda3d.core import Vec4

from direct.showbase.ShowBase import ShowBase
from panda3d.core import LineSegs   # Used in 'grid' function
from panda3d.core import TextNode, InputDevice, loadPrcFileData, Vec3
from panda3d.core import TextPropertiesManager
from direct.gui.OnscreenText import OnscreenText

loadPrcFileData("", """
    default-fov 60
    notify-level-device debug
""")

# Informational text in the bottom-left corner.  We use the special \5
# character to embed an image representing the gamepad buttons.
INFO_TEXT = """Move \5lstick\5 to strafe, \5rstick\5 to turn
Press \5ltrigger\5 and \5rtrigger\5 to go down/up
Press \5face_x\5 to reset camera"""


class App(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        # Print all events sent through the messenger
        #self.messenger.toggleVerbose()

        # Set the Background color
        self.setBackgroundColor(0.0, 0.0, 0.0)

        # Set camera far clipping plane to 10,000 units
        self.camLens.setFar(100000)

        # Increase ambient light intensity
        ambientLight = AmbientLight('ambientLight')
        ambientLight.setColor(Vec4(0.8, 0.8, 0.8, 1))  # Adjust intensity as needed
        ambientLightNP = render.attachNewNode(ambientLight)
        render.setLight(ambientLightNP)
        
        self.lblWarning = OnscreenText(
            text = "No devices found",
            fg=(1,0,0,1),
            scale = .25)

        self.lblAction = OnscreenText(
            text = "Action",
            fg=(1,1,1,1),
            scale = .15)
        self.lblAction.hide()

        # Is there a gamepad connected?
        self.gamepad = None
        devices = self.devices.getDevices(InputDevice.DeviceClass.gamepad)
        if devices:
            self.connect(devices[0])

        # Accept device dis-/connection events
        self.accept("connect-device", self.connect)
        self.accept("disconnect-device", self.disconnect)

        self.accept("escape", exit)

        # Accept button events of the first connected gamepad
        self.accept("gamepad-back", exit)
        self.accept("gamepad-start", exit)
        self.accept("gamepad-face_x", self.reset)
        self.accept("gamepad-face_a", self.action, extraArgs=["face_a"])
        self.accept("gamepad-face_a-up", self.actionUp)
        self.accept("gamepad-face_b", self.action, extraArgs=["face_b"])
        self.accept("gamepad-face_b-up", self.actionUp)
        self.accept("gamepad-face_y", self.action, extraArgs=["face_y"])
        self.accept("gamepad-face_y-up", self.actionUp)

        self.environment = loader.loadModel("models/grid_master.gltf")
        self.environment.reparentTo(render)

        # Disable the default mouse-camera controls since we need to handle
        # our own camera controls.
        self.disableMouse()
        self.reset()
        self.grid()
        self.bounding()
        self.taskMgr.add(self.moveTask, "movement update task")

    def connect(self, device):
        """Event handler that is called when a device is discovered."""

        # We're only interested if this is a gamepad and we don't have a
        # gamepad yet.
        if device.device_class == InputDevice.DeviceClass.gamepad and not self.gamepad:
            print("Found %s" % (device))
            self.gamepad = device

            # Enable this device to ShowBase so that we can receive events.
            # We set up the events with a prefix of "gamepad-".
            self.attachInputDevice(device, prefix="gamepad")

            # Hide the warning that we have no devices.
            self.lblWarning.hide()

    def disconnect(self, device):
        """Event handler that is called when a device is removed."""

        if self.gamepad != device:
            # We don't care since it's not our gamepad.
            return

        # Tell ShowBase that the device is no longer needed.
        print("Disconnected %s" % (device))
        self.detachInputDevice(device)
        self.gamepad = None

        # Do we have any other gamepads?  Attach the first other gamepad.
        devices = self.devices.getDevices(InputDevice.DeviceClass.gamepad)
        if devices:
            self.connect(devices[0])
        else:
            # No devices.  Show the warning.
            self.lblWarning.show()

    def reset(self):
        """Reset the camera to the initial position."""

        self.camera.setPosHpr(0, -200, 10, 0, 0, 0)

    def action(self, button):
        # Just show which button has been pressed.
        self.lblAction.text = "Pressed \5%s\5" % button
        self.lblAction.show()

    def actionUp(self):
        # Hide the label showing which button is pressed.
        self.lblAction.hide()

    def moveTask(self, task):
        dt = globalClock.getDt()

        if not self.gamepad:
            return task.cont

        strafe_speed = 850
        vert_speed = 5000
        turn_speed = 1000

        # If the left stick is pressed, we will go faster.
        lstick = self.gamepad.findButton("lstick")
        if lstick.pressed:
            strafe_speed *= 5.0

        # we will use the first found gamepad
        # Move the camera left/right
        strafe = Vec3(0)
        left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
        left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
        strafe.x = left_x.value
        strafe.y = left_y.value

        # Apply some deadzone, since the sticks don't center exactly at 0
        if strafe.lengthSquared() >= 0.01:
            self.camera.setPos(self.camera, strafe * strafe_speed * dt)

        # Use the triggers for the vertical position.
        trigger_l = self.gamepad.findAxis(InputDevice.Axis.left_trigger)
        trigger_r = self.gamepad.findAxis(InputDevice.Axis.right_trigger)
        lift = trigger_r.value - trigger_l.value
        self.camera.setZ(self.camera.getZ() + (lift * vert_speed * dt))

        # Move the camera forward/backward
        right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
        right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

        # Again, some deadzone
        if abs(right_x.value) >= 0.1 or abs(right_y.value) >= 0.1:
            self.camera.setH(self.camera, turn_speed * dt * -right_x.value)
            self.camera.setP(self.camera, turn_speed * dt * right_y.value)

            # Reset the roll so that the camera remains upright.
            self.camera.setR(0)

        return task.cont

    def grid(self):
        self.line1 = LineSegs("lines");
        self.line1.setColor(0.5, 0.5, 0.5, 1);    # R G B A, where A is tansparency or Alpha
        self.line1.setThickness(1.0)

        gridspacing = 1000.0
        ax = -40000.0
        ay = -20000.0
        bx = 40000.0
        by = -20000.0

        for n in range(21):
            self.line1.moveTo(ax, ay, 0.0);
            self.line1.drawTo(bx, by, 0.0);
            ay = ay + gridspacing
            by = by + gridspacing
            self.segsnode = self.line1.create(False);
            render.attachNewNode(self.segsnode);

        # Reset the
        ax = -40000.0
        ay = -20000.0
        bx = -40000.0
        by = 20000.0

        for n in range(41):
            self.line1.moveTo(ax, ay, 0.0);
            self.line1.drawTo(bx, by, 0.0);
            ax = ax + gridspacing
            bx = bx + gridspacing
            self.segsnode = self.line1.create(False);
            render.attachNewNode(self.segsnode);

    def bounding(self):
        self.line1 = LineSegs("lines");
        self.line1.setColor(1, 0, 0, 1);    # R G B A, where A is tansparency or Alpha
        self.line1.setThickness(1.0)
        # X  Y  Z
        p1 = (-40000.0, -20000.0, -20000.0)
        p2 = (40000.0, -20000.0, -20000.0)
        p3 = (40000.0, 20000.0, -20000.0)
        p4 = (-40000.0, 20000.0, -20000.0)
        p5 = (-40000.0, -20000.0, 20000.0)
        p6 = (40000.0, -20000.0, 20000.0)
        p7 = (40000.0, 20000.0, 20000.0)
        p8 = (-40000.0, 20000.0, 20000.0)
        nodes = [p1, p2, p3, p4, p5, p6, p7, p8]
        ia = 0
        ib = 0
        ic = 0
        # Start of line Segment
        for a in nodes:
            x1 = a[0]
            y1 = a[1]
            z1 = a[2]
            # End of line Segment
            for b in nodes:
                x2 = b[0]
                y2 = b[1]
                z2 = b[2]

        #---Bounding Box---#

        # Lower bounding square border
        self.line1.moveTo(p1);
        self.line1.drawTo(p2);
        self.line1.drawTo(p3);
        self.line1.drawTo(p4);
        self.line1.drawTo(p1);

        # Upper bounding square border
        self.line1.moveTo(p5);
        self.line1.drawTo(p6);
        self.line1.drawTo(p7);
        self.line1.drawTo(p8);
        self.line1.drawTo(p5);

        self.line1.moveTo(p1);
        self.line1.drawTo(p5);
        self.line1.drawTo(p1);

        self.line1.moveTo(p2);
        self.line1.drawTo(p6);
        self.line1.drawTo(p2);

        self.line1.moveTo(p3);
        self.line1.drawTo(p7);
        self.line1.drawTo(p3);

        self.line1.moveTo(p4);
        self.line1.drawTo(p8);
        self.line1.drawTo(p4);

        self.segsnode = self.line1.create(False);
        render.attachNewNode(self.segsnode);

app = App()
app.run()

… Don’t ask ChatGPT for useful advice, please. It’ll tell you–with full apparent “confidence”–complete nonsense.

In this specific case, yes, its response seems unlikely to be accurate. The “point” regarding fog in particular makes no real sense to me.

Now, as to your question, I’m not sure of what specifically is happening, but as I recall there are issues with using very large floating-point numbers–as in the case of moving to a position very, very far from the origin.

To be clear, this is less a limitation of Panda3D than a limitation of floating point numbers. It’s possible, of course, that there are engines that have built-in solutions to this; I don’t know.

I’ve seen threads on similar topics in the past, as I recall–see this one, for example.

In short, there are a few potential solutions, if this is indeed the source of your issue. For two, you could try recompiling Panda to use double-precision floats (although even that has limitations), or you could try shifting the world such that the camera never gets all that far from the origin.

I’m not confident of this next, but I’m also not sure that a far-distance of 100, 000 is wise: you might find that you hit some depth-buffer precision issues with that. But I stand to be corrected!

I created a quick test from your code, I don’t see any problems.

#!/usr/bin/env python3

from direct.showbase.ShowBase import ShowBase
from panda3d.core import LineSegs, TextNode, loadPrcFileData, Vec3, AmbientLight, Vec4

loadPrcFileData("", """
    default-fov 60
""")

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

        self.setBackgroundColor(0.0, 0.0, 0.0)
        self.camLens.setFar(1000000000)

        # Increase ambient light intensity
        ambientLight = AmbientLight('ambientLight')
        ambientLight.setColor(Vec4(0.8, 0.8, 0.8, 1))  # Adjust intensity as needed
        ambientLightNP = render.attachNewNode(ambientLight)
        render.setLight(ambientLightNP)

        self.accept("escape", exit)
        self.accept("space", self.teleport)

        self.grid()
        self.bounding()

        self.step = 5000

    def teleport(self): 
        self.step = self.step*2
        self.cam.setPos(0, -self.step, 0)
        print(self.cam.get_pos())

    def grid(self):
        self.line1 = LineSegs("lines");
        self.line1.setColor(0.5, 0.5, 0.5, 1);    # R G B A, where A is tansparency or Alpha
        self.line1.setThickness(1.0)

        gridspacing = 1000.0
        ax = -40000.0
        ay = -20000.0
        bx = 40000.0
        by = -20000.0

        for n in range(21):
            self.line1.moveTo(ax, ay, 0.0);
            self.line1.drawTo(bx, by, 0.0);
            ay = ay + gridspacing
            by = by + gridspacing
            self.segsnode = self.line1.create(False);
            render.attachNewNode(self.segsnode);

        # Reset the
        ax = -40000.0
        ay = -20000.0
        bx = -40000.0
        by = 20000.0

        for n in range(41):
            self.line1.moveTo(ax, ay, 0.0);
            self.line1.drawTo(bx, by, 0.0);
            ax = ax + gridspacing
            bx = bx + gridspacing
            self.segsnode = self.line1.create(False);
            render.attachNewNode(self.segsnode);

    def bounding(self):
        self.line1 = LineSegs("lines");
        self.line1.setColor(1, 0, 0, 1);    # R G B A, where A is tansparency or Alpha
        self.line1.setThickness(1.0)
        # X  Y  Z
        p1 = (-40000.0, -20000.0, -20000.0)
        p2 = (40000.0, -20000.0, -20000.0)
        p3 = (40000.0, 20000.0, -20000.0)
        p4 = (-40000.0, 20000.0, -20000.0)
        p5 = (-40000.0, -20000.0, 20000.0)
        p6 = (40000.0, -20000.0, 20000.0)
        p7 = (40000.0, 20000.0, 20000.0)
        p8 = (-40000.0, 20000.0, 20000.0)
        nodes = [p1, p2, p3, p4, p5, p6, p7, p8]
        ia = 0
        ib = 0
        ic = 0
        # Start of line Segment
        for a in nodes:
            x1 = a[0]
            y1 = a[1]
            z1 = a[2]
            # End of line Segment
            for b in nodes:
                x2 = b[0]
                y2 = b[1]
                z2 = b[2]

        #---Bounding Box---#

        # Lower bounding square border
        self.line1.moveTo(p1);
        self.line1.drawTo(p2);
        self.line1.drawTo(p3);
        self.line1.drawTo(p4);
        self.line1.drawTo(p1);

        # Upper bounding square border
        self.line1.moveTo(p5);
        self.line1.drawTo(p6);
        self.line1.drawTo(p7);
        self.line1.drawTo(p8);
        self.line1.drawTo(p5);

        self.line1.moveTo(p1);
        self.line1.drawTo(p5);
        self.line1.drawTo(p1);

        self.line1.moveTo(p2);
        self.line1.drawTo(p6);
        self.line1.drawTo(p2);

        self.line1.moveTo(p3);
        self.line1.drawTo(p7);
        self.line1.drawTo(p3);

        self.line1.moveTo(p4);
        self.line1.drawTo(p8);
        self.line1.drawTo(p4);

        self.segsnode = self.line1.create(False);
        render.attachNewNode(self.segsnode);

app = App()
app.run()

Indeed, trying the code from the original post now–albeit hacked to not require that a gamepad be plugged in, instead just flying off by itself, and to look down on the grid–I don’t seem to be seeing the grey screen that was described.

For reference, I let the camera fly out to a y-value of about 400 000.

So let me ask: how far out does the camera have to be in order to get the grey screen?

I begin to wonder whether the problem might not be a hardware or driver issue–maybe some graphics cards have idiosyncratic trouble with very big floating-point numbers, or some such thing?

So there must be some other problem.
@Thaumaturge I just copy pasted the code you wrote my screen all black with nothing showing.

since you both having no issues there must be something else.

I’ve always had this error message show when I run a script but google said it was nothing;

Known pipe types:
glxGraphicsPipe
(1 aux display modules not yet loaded.)
Xlib: extension “XFree86-DGA” missing on display “:0”.
:device(warning): /dev/input/event4 is not readable, some features will be unavailable.

(For the record, I only use chatGPT as a sorta extra tool, a last ditch effort.
it solves my issue .1 % of the time lol)

I will also try this script from another computer. (also im on Linux, will try from windoze)

thanxs again

I think that that was serega, not me, that posted that code. ^^;

But still, did you try moving the mouse around, with either the left- or (preferably) middle- mouse-button held?

The code posted by serega places the camera initially at the same height as the grid and looking out along the plane of the grid, thus making it potentially hard to see without first adjusting the view.

Hmm, this is interesting…

Looking at this old thread, perhaps it’s worth looking into fixing the issue and seeing whether that helps?

On a related note, a bit of quick searching prompts me to ask: are you by any chance using an integrated Intel graphics chipset? (i.e. As opposed to a dedicated graphics card/chipset.)

(I’m also on Linux, by the way.)

so dumb, I wasted everybodies time!

on lines 80 / 81 I had a model loaded,
#self.environment = loader.loadModel(“models/grid_master.gltf”)
#self.environment.reparentTo(render)

I thought I had removed it.

works fine, human error. and I’ve been up and down the code 100 times :frowning:

Thanks for the help.

I did try from windows machine and gamepad was all squirly, but works fine in Linux.
I think ‘dead zones’ need to be set for it to work properly in windows.

1 Like

I thought those who want to test the code would see that I use a space + mouse…

Ah, you’re right!

And I think that I did see that… and then forgot! XD;