lod example

I have a question,
how to create lod with panda3D ?
How it’s work, can i load objet et change texture quality (Depending on the distance where I am)
or i must to load/reload objet with more or less details ?

can i have a basic example ?

Which 3d format is the most suitable ? I prefer “open” format (like fbx, 3mf…) that egg or bam, it’s possible to use this formats in last developpement version of panda3D ?

thanks for advance.

i try with lod function in documentation but it’s not work:

#!/usr/bin/env python

from direct.showbase.ShowBase import ShowBase
from panda3d.core import Filename, Texture
from panda3d.core import AmbientLight, DirectionalLight, PointLight, LODNode
from panda3d.core import NodePath, TextNode
from direct.task.Task import Task
from direct.actor.Actor import Actor
from direct.gui.OnscreenText import OnscreenText
import sys
import os
import random

random.seed()

class TeapotOnTVDemo(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        self.disableMouse()
        self.setBackgroundColor((0, 0, 0, 1))
        
        
        lod = LODNode('my LOD node')
        self.lod_np = NodePath(lod)
        self.lod_np.reparentTo(render)
        lod.addSwitch(0.5, 0.0)

        # we now get buffer thats going to hold the texture of our new scene
        altBuffer = self.win.makeTextureBuffer("hello", 256, 256)

        # Create the tv-men. Each TV-man will display the
        # offscreen-texture on his TV screen.
        self.tvMen = []
        self.makeTvMan(0, 100, -3, altBuffer.getTexture(), 2.0)

        self.accept("escape", sys.exit, [0])

    def makeTvMan(self, x, y, z, tex, playrate):
        man = Actor()
        man.loadModel('models/mechman_idle')
        man.setPos(x, y, z)
        #man.reparentTo(render)
        man.reparentTo(self.lod_np)
        faceplate = man.find("**/faceplate")
        faceplate.setTexture(tex, 1)
        man.setPlayRate(playrate, "mechman_anim")
        man.loop("mechman_anim")
        self.tvMen.append(man)

demo = TeapotOnTVDemo()
demo.run()

normaly this function hide distant object, but i want too change medium object texture with low texture.

You can use the LODNode like this:

#1. make a LODNode and a NodePath wrapper for that LODNode
model_lod = LODNode('model_lod')
model = NodePath(model_lod)
#2. empty node, we won't show a model far far away
lod2 = NodePath('far_far_away')
lod2.reparentTo(model)
model_lod.addSwitch(1000, 300)
#3. load a low poly model for medium distance
lod1 = loader.loadModel("low_poly_model") 
lod1.reparentTo(model)
model_lod.addSwitch(300, 150)
#4. high poly model for close up
lod0 = loader.loadModel("hi_poly_model")
lod0.reparentTo(model)
model_lod.addSwitch(150, 0)

model.reparentTo(render)

So you make the LODNode and add NodePath, put the LODNode in the NodePath, then reparent models (nodes) to that NodePath walking from the furthest to the closest adding the lod switch distances as you go along.

But I think that using LODs for lower resolution textures is counter productive, you have mip maps for that, your gpu (or driver, or panda3d, that may depend?) will auto-magically generate smaller versions of your texture and use that texture size that fits closest to the on screen size of the textured object (+ some filtering), all you got to do is set the filter to anything with ‘mipmap’ in its name (like ‘FT_nearest_mipmap_nearest’) - and I think that’s also the default filter type in Panda3D.

You can manually set a different (smaller) texture for a model in a LODNode, but you’re not saving memory this way - you’ll have both the smaller and bigger texture loaded.

If you want to resize a texture buffer, then you can do that… but I think you need to use the makeOutput interface to set the right flags -GraphicsPipe.BF_resizeable - (and get a FBO not the… em… other thing pbuffer? IDK), then you can change the size just using buffer.setSize(X,Y). I have no idea how changing the size of a buffer affects performance, but I don’t think that’s something you would want to do every frame.

#altBuffer = self.win.makeTextureBuffer("hello", 256, 256) #no

winprops = WindowProperties()
winprops.setSize(256, 256)
props = FrameBufferProperties()
props.setRgbColor(True)
props.setRgbaBits(8, 8, 8, 8)
props.setDepthBits(0)
sort=-1
some_texture=Texture()
altBuffer = base.graphicsEngine.makeOutput(
    base.pipe, 'hello', sort,
    props, winprops,
    GraphicsPipe.BF_resizeable,
    base.win.getGsg(), base.win)
    
altBuffer.addRenderTexture(
    tex=some_texture, mode=GraphicsOutput.RTMBindOrCopy,
    bitplane=GraphicsOutput.RTPColor)

ok thanks for your answer and your solution work :slight_smile:

For you, change the resolution of textures is not important ? because panda Engine and gpu driver change resolution automatiquely ?

The equivalent to LOD for textures is called “mipmapping”. If you enable this on your textures, the GPU will automatically generate lower resolution versions of your texture as well as figure out which LOD level to use for each texture.

Mipmap filtering is not enabled by default, but you can do this by setting a Config.prc variable setting.