Hello, to improve performance, I would like my distant objects to be 2d images. (transparent png).
from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenImage import OnscreenImage
from direct.actor.Actor import Actor
from panda3d.core import *
import random
from panda3d.core import loadPrcFileData
class Application(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.setFrameRateMeter(True)
self.panda = Actor("panda", {"walk": "panda-walk"})
self.panda.reparentTo(render)
self.panda.loop("walk")
self.cam.setPos(0, -30, 5)
files = ["myimage.png"]
for i in range(30):
OnscreenImage(random.sample(files, 1)[0],
scale = Vec3(0.1, 0.1, 0.1),
pos = Vec3(random.uniform(-1, 1), 0, random.uniform(-1, 1)),
hpr = Vec3(0, 0, random.uniform(0, 360)))
self.run()
config_data = """
sync-video false
"""
loadPrcFileData("", config_data)
app = Application()
I have 2 problems with my code:
the images remain fixed on the screen, Iād like them to be placed in 3d, like my panda object in 3d. Iād like them to move away when I move backwards and get bigger when I move closer.
the png is displayed in a black rectangle, can I make it transparent?
In short, the answer two both questions is simply that an OnscreenImageālike (I think) all classes that render something on-screenāis a NodePath, and can be treated like any other NodePath.
To answer in specific:
This is because, by default, OnscreenImage is a child of the 2D scene-graph (aspect2d, to be specific), I believe.
I see two ways of approaching what you want, broadly speaking:
First and simplest, the constructor for OnscreenImage takes a āparentā parameter; just pass into this parameter whatever node in the 3D scene you want the image to be attached to.
Second, and mentioned mainly for illustrative purposes, is that you could simply reparent the OnscreenImage to the desired node in the 3D sceneāas I said, itās a NodePath.
You should be able (as again with pretty much any NodePath) to either call āsetTransparentā on your OnscreenImage, or reparent it below a node that has been set to use transparency.
I thought that a simple image2d would be more efficient than loading the 3d model.
Iād like to display a huge army (1000000 soldiers) moving around. I thought that the 1st closest models would be in 3d and would have physics.
the far soldiers would be in 2d with no physics
Iāve already tried lodnode but I donāt think itās powerful enough.
is it possible to display 1 million panda object ?
Iāve reduced the size of the distant elements, if you have a code to reduce the geometry of an object Iām interested.
I was thinking, displaying 1 million pandas in 2d shouldnāt require a lot of resources compared to 3d objects, should it?
Oh wow; having that many objects is going to call for a rather more advanced approach than this, with LODNode or not! 0_0
In short, having so many on screen at once, and having them move independently, would I think call for some shader-work; I donāt know the specifics (not having done such myself), but someone else here might know how itās done.
Of course, there is the simpleābut less dynamicāapproach: have a few 2D objects each showing a large group of soldiers.
If those pandas are independent objects in the scene-graph (or other structure as appropriate), then I think that it would be pretty costly in any engine. o_o
year, I would like to use this approach:
āOf course, there is the simpleābut less dynamicāapproach: have a few 2D objects each showing a large group of soldiers.ā
to do this I need to be able to position my 2d objects in 3d space.
I tested it but with 10000 images it becomes very slow, I didnāt think it would be so slow.
is there any other solution for displaying lots of objects in 2d efficiently?
To improve performance Iām trying to create a single NodePath containing all the maps using Geom classes. This considerably reduces the number of nodes in the scene and improves performance.
from direct.showbase.ShowBase import ShowBase
from panda3d.core import CardMaker, NodePath, Texture, TextureStage, Vec4
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.setFrameRateMeter(True)
texture = self.loader.load_texture("texture.png")
self.render.set_transparency(True)
face_maker = CardMaker("face")
face_maker.set_frame(-1, 1, -1, 1)
group_np = NodePath("group")
num_cards = 10000
cards_per_row = 100
spacing = 1.5
row_spacing = 1.5
vertex_data_format = GeomVertexFormat.get_v3c4()
vertex_data = GeomVertexData("vertices", vertex_data_format, Geom.UHStatic)
vertex_writer = GeomVertexWriter(vertex_data, "vertex")
color_writer = GeomVertexWriter(vertex_data, "color")
for i in range(num_cards):
x = (i % cards_per_row) * spacing
y = (i // cards_per_row) * row_spacing
vertex_writer.add_data3(x, y, 0)
color_writer.add_data4(1, 1, 1, 1)
prim = GeomTriangles(Geom.UHStatic)
for i in range(num_cards):
row_length = cards_per_row
if i // cards_per_row == num_cards // cards_per_row:
row_length = num_cards % cards_per_row
if i % cards_per_row != row_length - 1 and i // cards_per_row != num_cards // cards_per_row:
v0 = i
v1 = i + 1
v2 = i + cards_per_row
v3 = i + cards_per_row + 1
prim.add_vertices(v0, v1, v2)
prim.add_vertices(v1, v3, v2)
geom = Geom(vertex_data)
geom.add_primitive(prim)
node = GeomNode("geom_node")
node.add_geom(geom)
face_np = NodePath(node)
face_np.set_texture(texture)
face_np.reparent_to(group_np)
group_np.set_pos(0, 0, 0)
group_np.reparent_to(self.render)
app = MyApp()
app.run()
but Iām getting errors using āGeomVertexFormatā.
You can similarly use the flatten_strong method. And also you can try RigidBodyCombiner.
from panda3d.core import NodePath
from direct.showbase.ShowBase import ShowBase
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
all_node = NodePath('all')
for i in range(0, 10):
for j in range(0, 10):
model = loader.load_model("panda")
model.clear_model_nodes()
model.set_pos(i*10, j*10, 0)
model.reparent_to(all_node)
all_node.flatten_strong()
all_node.reparent_to(render)
print(all_node.ls())
app = MyApp()
app.run()
To the best of my knowledge, no, itās not possible. (Or at least, not easily so.) As you say, the objects are I believe combined into a single nodeāindeed, a single model.
You could perhaps try the āRigidBodyCombinerā, which might allow this facility, or implement your cards instead via āMeshDrawerā.
As a quick proof of concept, I modified your earlier code slightly (from Post 14).
I made each row a single image (that was cards_per_row wide) that had U part of the texture coordinates from 0 to cards_per_row and made the texture wrap in the U dimension.
Now obviously there are caveats with this approach, like they must be identical, and things like your spacing parameter are probably going to be static. (To get our different approaches to be identical I had to remove the variable spacing.)
Hope thatās useful somewhat
And best of luck with your project!