90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
import direct
|
||
import direct.showbase
|
||
import direct.showbase.ShowBaseGlobal
|
||
import panda3d.core as p3d
|
||
from direct.showbase.ShowBase import ShowBase
|
||
from panda3d.core import NodePath
|
||
|
||
class GameObject(NodePath):
|
||
def __init__(self, model: NodePath):
|
||
self = model
|
||
self.gameobject = self
|
||
self.self_active = self.is_hidden()
|
||
|
||
def set_active(self, active: bool):
|
||
if active:self.show()
|
||
else:self.hide()
|
||
|
||
@classmethod
|
||
def create_panel(self) -> NodePath:
|
||
base = direct.showbase.ShowBaseGlobal.base
|
||
if not base or not base.render:
|
||
raise Exception("base or base.render is None")
|
||
from panda3d.core import CardMaker
|
||
cm = CardMaker("ground")
|
||
cm.set_frame(-10, 10, -10, 10) # (left, right, bottom, top)
|
||
plane_np = base.render.attach_new_node(cm.generate())
|
||
plane_np.set_hpr(0, -90, 0) # 躺平(默认是 XY 平面,朝 +Z)
|
||
plane_np.setTwoSided(True)
|
||
mat = p3d.Material('unlit')
|
||
plane_np.set_material(mat)
|
||
return plane_np
|
||
|
||
@classmethod
|
||
def set_model_auto_scale(self, model: NodePath,debug_info = False):
|
||
base = direct.showbase.ShowBaseGlobal.base
|
||
if not base or not base.render:
|
||
raise Exception("base or base.render is None")
|
||
|
||
if not model or model.is_empty():
|
||
return
|
||
|
||
bmin, bmax = model.get_tight_bounds(base.render)
|
||
if bmin is None or bmax is None:
|
||
return
|
||
|
||
size = bmax - bmin
|
||
max_size = max(size.x, size.y, size.z)
|
||
|
||
if max_size <= 0:
|
||
return
|
||
|
||
# 目标:让最大边缩放到略小于 10,比如 9.9
|
||
target_max = 3
|
||
scale_factor = target_max / max_size
|
||
|
||
model.set_scale(scale_factor)
|
||
|
||
if debug_info:
|
||
print(f"自动缩放:原最大尺寸={max_size:.3f} → 缩放因子={scale_factor:.6f}")
|
||
|
||
@classmethod
|
||
def get_node_type(self,np: NodePath) -> str:
|
||
node = np.node()
|
||
|
||
if isinstance(node, p3d.GeomNode):
|
||
return "mesh(GeomNode)"
|
||
if isinstance(node, p3d.CollisionNode):
|
||
return "collision(CollisionNode)"
|
||
if isinstance(node, p3d.Camera):
|
||
return "camera"
|
||
if isinstance(node, p3d.Light):
|
||
return "light"
|
||
if isinstance(node, p3d.TextNode):
|
||
return "text"
|
||
|
||
# 不同节点可能是模型根、LOD根等,但核心是:是否包含 Geom/Collision
|
||
if not np.find("**/+GeomNode").isEmpty():
|
||
return "empty*"
|
||
if not np.find("**/+CollisionNode").isEmpty():
|
||
return "collision_parent*"
|
||
return "empty"
|
||
|
||
@classmethod
|
||
def get_child_name(self,node:NodePath):
|
||
if not node or node.isEmpty() or node.getNumChildren() == 0:return
|
||
for n in node.getChildren():
|
||
print(f"{n.getName()} -> {GameObject.get_node_type(n)}")
|
||
GameObject.get_child_name(n)
|
||
|
||
return f"empty/transform({node.getType().getName()})" |