Loading a model by creating a seperate py file

@iamlrk
Please note that the second option is suitable for you, so you will continue to load actors.

Okay, Thanks for the help!!

If the def __init__(self): method you don’t need it for logic, you can just delete it.

file: ModelLoader.py

class loadMyModel():
    def load(self, base, model):
        ob = base.loader.loadModel(model)
        return ob
1 Like

Conversely, I’d suggest that in that case a class is superfluous. The code could then be simplified to something like the following:

In “ModelLoader.py”:

# Note that there's no class here at all!
def loadAModel(base, model):
    obj = base.loader.loadModel(model)
    return obj

In “main.py”:

from direct.showbase.ShowBase import ShowBase
from ModelLoader import loadAModel

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

        self.panda = loadAModel(self, "panda")

        self.box = loadAModel(self, "box")

(I do still advocate for the use of a “common”-file, however: I think that it comes to be rather less unwieldy as the program scales up.)

I think it’s better for the author to know why he needs the class. It may want to make a counter of loaded models.

file: ModelLoader.py

class loadMyModel():
    def __init__(self):
        self.count_models = 0

    def load(self, base, model):
        ob = base.loader.loadModel(model)
        self.count_models +=1

        return ob

file: main.py

from direct.showbase.ShowBase import ShowBase

from ModelLoader import loadMyModel

class MyApp(ShowBase):

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

        load_my_model = loadMyModel()

        self.panda = load_my_model.load(base, "panda")
        self.panda.setPos(0, 5, 0)
        self.panda.reparentTo(render)

        self.box = load_my_model.load(base, "box")
        self.box.setPos(0, -5, 0)
        self.box.reparentTo(render)
        
        print(load_my_model.count_models)

app = MyApp()
app.run()

I do not understand why to pass access to the main application class?

Yes, but that was in response to your suggestion that the __init__ method could be removed. I was saying that, in that case, it seemed plausible that one could do without the class entirely.

The original poster knows what they’re making–let us suggest options, and them decide between those.

That’s what you were doing in your version, too: “base” is a variable that references the current “ShowBase” instance, and in the case in which the main application class derives from
“ShowBase”, that “ShowBase” instance is in fact the current instance of the main application class.

Obviously, it is better to keep the readability and convey really what you need. I mean the name “base” is more informative.

After all, we have another type of initialization, ShowBase.

from direct.showbase.ShowBase import ShowBase

base = ShowBase()

model = base.loader.loadModel("panda")
model.reparentTo(render)

base.run()

It will be interchangeable.

The self itself is misleading. It is not at all clear where this fashion came from to use it everywhere. Of course, I understand that we have expanded the ShowBase class, but it is better to save the name in order to understand what comes from where.

I would say that different contexts call for different uses.

I don’t think so. The application class is a descendant of ShowBase, so by standard Object-Orientation is has everything that ShowBase has. Thus the use of “self” does indicate what came from where.

If anything, I’d argue that the free-floating “base”-variable is less clear.

However, this might be a matter of personal coding preferences!

As I said above, using ShowBase is not your application. And to use inheritance from it without an internal understanding of its structure, is fraught with a rake in the grass.

By that logic, one shouldn’t use a third-party engine at all: most of the contents are going to be things the internals of which one doesn’t understand, or at least hasn’t studied.

An application that extends ShowBase is very much one’s own application, I would argue. It’s just one that uses ShowBase as a foundation, allowing it to build higher without worrying as much about the fundamentals.

This is what I was talking about, just a demonstration of the engine. But in reality, this may not be suitable for your application.

I don’t see how what I said indicates that at all.

In the contrary, I’m saying that an application built on ShowBase is very much its own thing, while inheriting the features–which I feel are useful–that ShowBase provides.

Possibly–but rarely, I would imagine. I know that it’s been rather useful for pretty much all of mine, as far as I recall!

[edit 2]
“Pretty much all of my projects since I stopped using the ‘DirectStart’ approach”, at least, if I recall correctly.
[/edit 2]

[edit]
But look, we’ve strayed from the point of this thread. The original poster has found a solution to their issue, and we’ve each offered our takes on what they were doing–let’s leave it here and agree to disagree, yes?

Note what I said about the universal approach, you need to initialize the engine yourself from start to finish for your application. To get rid of many problems in the future.

However, you insist that rakes are sometimes useful.

No, I insist that you’re seeing rakes where there are none. :stuck_out_tongue:

As I said, I strongly disagree. Indeed, I’ve had no such troubles that I recall from this method, across a number of projects!

In fact, the continuation of this topic is legal. So the result of this problem is in the ShowBase architecture.

Perhaps the solution will be to use the Loader class directly from direct, but this needs to be checked.

We really need to get away from using the ‘ShowBase’ instance unnecessarily. To make the code look more modular and independent. Like here:

Honestly, that just looks more unwieldy to me. ShowBase is convenient, and works well.

Why go through the matter of getting the global pointer, storing it in a variable of one’s own, and then using that, when one can just use the version already stored in a variable by ShowBase? I see little functional difference, and more convolution, myself.

I’m not sure of what you mean here. If you’re saying that the original poster’s issue came about because of the use of ShowBase, then, again, I disagree: the problem seemed to me to step more from matters of Python-usage than matters of ShowBase-usage.

Do you understand that it is strange to require an instance of the application for the download operation.

I think that I see what you’re saying.

But in this case, it’s a convenience: ShowBase gathers together a bunch of commonly-useful items in one place, and thus makes them more-easily accessible. And I’m happy to give up a little bit of theoretical-correctness for that convenience, personally.

The question of convenience is questionable.

Today I wrote a module: ModelLoader.py

from panda3d.core import Loader, NodePath

class loadMyModel():
    def __init__(self):
        self.loader = Loader.get_global_ptr()

    def load(self, model):
        ob = self.loader.load_sync(model)

        return NodePath(ob)

In the future, I can use it anywhere, without passing any links.

from panda3d.core import *
from ModelLoader import loadMyModel

load_my_model = loadMyModel()

engine = GraphicsEngine.get_global_ptr()
pipe = GraphicsPipeSelection.get_global_ptr().make_default_pipe()

# Open a window with requested properties
fb_prop = FrameBufferProperties()
fb_prop.rgb_color = 1
fb_prop.color_bits = 3 * 8
fb_prop.depth_bits = 24
fb_prop.back_buffers = 1
win = engine.make_output(pipe, name="window", sort=0, fb_prop=fb_prop,
                         win_prop=WindowProperties(size=(800, 600)),
                         flags=GraphicsPipe.BF_require_window)

# Set a grey background color
win.set_clear_color_active(True)
win.set_clear_color((0.5, 0.5, 0.5, 1))

# Create a scene and camera to render
render = NodePath("render")
cam = render.attach_new_node(Camera("camera"))
cam.node().set_lens(PerspectiveLens())

model = load_my_model.load("panda")
model.reparentTo(render)
model.set_pos(0, 100, 0)

# Create a display region that renders this scene
dr = win.make_display_region()
dr.camera = cam

# You could use the task manager and create a task that does this,
# but I wanted to show how to do it directly
while not win.is_closed():
    engine.render_frame()
1 Like