EG/scene/scene_manager_light_mixin.py
2026-02-27 16:52:00 +08:00

456 lines
19 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Scene manager light operations."""
import os
import shutil
import time
import json
import aiohttp
import asyncio
import inspect
from pathlib import Path
from panda3d.core import (
ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3,
MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, CollisionBox,
BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib
)
from panda3d.egg import EggData, EggVertexPool
from direct.actor.Actor import Actor
from RenderPipelineFile.rpplugins.smaa.jitters import halton_seq
from scene import util
class SceneManagerLightMixin:
def _recreateSpotLight(self, light_node):
"""重新创建聚光灯"""
try:
from RenderPipelineFile.rpcore import SpotLight
from panda3d.core import Vec3
from core.render_pipeline_utils import get_render_pipeline
# 创建聚光灯对象
light = SpotLight()
light.direction = Vec3(0, 0, -1)
light.fov = 70
light.set_color_from_temperature(5 * 1000.0)
# 恢复保存的属性
if light_node.hasTag("light_energy"):
light.energy = float(light_node.getTag("light_energy"))
else:
light.energy = 5000
light.radius = 1000
light.casts_shadows = True
light.shadow_map_resolution = 256
light_pos = light_node.getPos()
light.setPos(light_pos)
# 添加到渲染管线
render_pipeline = get_render_pipeline()
render_pipeline.add_light(light)
# 保存光源对象引用
light_node.setPythonTag("rp_light_object", light)
# 添加到管理列表(去重)
if light_node not in self.Spotlight:
self.Spotlight.append(light_node)
# 确保灯光节点有正确的标签,以便在场景树更新时被识别
if not light_node.hasTag("is_scene_element"):
light_node.setTag("is_scene_element", "1")
light_node.setTag("is_scene_element", "1")
light_node.setTag("element_type", "spotlight")
light_node.setTag("tree_item_type", "LIGHT_NODE")
if light_node.hasTag("stored_energy"):
stored_energy = float(light_node.getTag("stored_energy"))
if stored_energy > 0:
light_node.setTag("stored_energy", str(stored_energy))
user_visible = True
if light_node.hasTag("user_visible"):
user_visible = light_node.getTag("user_visible").lower() == "true"
light_node.setPythonTag("user_visible",user_visible)
if not user_visible:
self.toggleLightVisibility(light_node,False)
except Exception as e:
print(f"重新创建聚光灯失败: {str(e)}")
import traceback
traceback.print_exc()
def _recreatePointLight(self, light_node):
"""重新创建点光源"""
try:
from RenderPipelineFile.rpcore import PointLight
from core.render_pipeline_utils import get_render_pipeline
# 创建点光源对象
light = PointLight()
# 恢复保存的属性
if light_node.hasTag("light_energy"):
light.energy = float(light_node.getTag("light_energy"))
else:
light.energy = 5000
light.radius = 1000
light.inner_radius = 0.4
light.set_color_from_temperature(5 * 1000.0)
light.casts_shadows = True
light.shadow_map_resolution = 256
# 设置位置
light.setPos(light_node.getPos())
# 添加到渲染管线
render_pipeline = get_render_pipeline()
render_pipeline.add_light(light)
# 保存光源对象引用
light_node.setPythonTag("rp_light_object", light)
# 添加到管理列表(去重)
if light_node not in self.Pointlight:
self.Pointlight.append(light_node)
# 确保灯光节点有正确的标签,以便在场景树更新时被识别
if not light_node.hasTag("is_scene_element"):
light_node.setTag("is_scene_element", "1")
light_node.setTag("is_scene_element", "1")
light_node.setTag("element_type", "pointlight")
light_node.setTag("tree_item_type", "LIGHT_NODE")
if light_node.hasTag("stored_energy"):
stored_energy = float(light_node.getTag("stored_energy"))
if stored_energy > 0:
light_node.setTag("stored_energy", str(stored_energy))
user_visible = True
if light_node.hasTag("user_visible"):
user_visible = light_node.getTag("user_visible").lower()=="true"
light_node.setPythonTag("user_visible",user_visible)
if not user_visible:
self.toggleLightVisibility(light_node,False)
except Exception as e:
print(f"重新创建点光源失败: {str(e)}")
import traceback
traceback.print_exc()
def isLightObject(self, nodePath):
"""检查是否为灯光对象"""
try:
if not nodePath:
return False
# 方法1: 检查PythonTag
if nodePath.hasPythonTag("rp_light_object"):
rp_light = nodePath.getPythonTag("rp_light_object")
if rp_light is not None:
return True
# 方法2: 检查element_type标签
if nodePath.hasTag("element_type"):
element_type = nodePath.getTag("element_type")
if element_type in ["spotlight", "pointlight"]:
return True
# 方法3: 检查tree_item_type标签
if nodePath.hasTag("tree_item_type"):
tree_item_type = nodePath.getTag("tree_item_type")
if tree_item_type == "LIGHT_NODE":
return True
# 方法4: 通过名称模式匹配(作为后备方案)
node_name = nodePath.getName().lower()
if "spotlight" in node_name or "pointlight" in node_name:
return True
return False
except Exception as e:
print(f"检查灯光对象时出错: {e}")
import traceback
traceback.print_exc()
return False
def toggleLightVisibility(self, light_node, visible):
"""切换灯光可见性"""
try:
print(f"切换灯光可见性: {light_node.getName()}, 可见={visible}")
# 保存用户可见性状态到该特定节点
light_node.setPythonTag("user_visible", visible)
# 获取该特定灯光对象
rp_light_object = light_node.getPythonTag("rp_light_object")
if not rp_light_object:
print(f"错误: {light_node.getName()} 未找到RP灯光对象引用")
return
# 获取RenderPipeline实例
from core.render_pipeline_utils import get_render_pipeline
render_pipeline = get_render_pipeline()
if not render_pipeline:
print("错误: 无法获取RenderPipeline实例")
return
try:
if visible:
if light_node.hasTag("stored_energy"):
stored_energy = float(light_node.getTag("stored_energy"))
rp_light_object.energy=stored_energy
print(f"已恢复灯光强度: {light_node.getName()}, 能量={stored_energy}")
# 启用特定灯光
# render_pipeline.add_light(rp_light_object)
# print(f"已添加灯光到渲染管线: {light_node.getName()}")
else:
# 禁用特定灯光
current_energy = rp_light_object.energy
if current_energy != 0.0:
light_node.setTag("stored_energy", str(current_energy))
elif light_node.hasTag("stored_energy"):
stored_energy = float(light_node.getTag("stored_energy"))
current_energy = stored_energy
else:
current_energy = 0.0
rp_light_object.energy = 0.0
print(f"已禁用灯光: {light_node.getName()}, 保存的能量={current_energy}")
# render_pipeline.remove_light(rp_light_object)
# print(f"已从渲染管线移除灯光: {light_node.getName()}")
except Exception as e:
print(f"操作RenderPipeline灯光时出错: {e}")
# 控制节点显示状态(可选,主要是视觉上的)
if visible:
light_node.show()
else:
light_node.hide()
print(f"灯光可见性设置完成: {visible}")
except Exception as e:
print(f"切换灯光可见性失败: {str(e)}")
import traceback
traceback.print_exc()
def _recreateLightFromData(self, node_data, parent_node, name):
"""根据数据重建光源"""
try:
light_type = node_data.get('tags', {}).get('light_type', 'spot_light')
# 创建光源
if light_type == 'spot_light':
light_node = self.createSpotLight(pos=node_data.get('pos', (0, 0, 0)))
else: # point_light
light_node = self.createPointLight(pos=node_data.get('pos', (0, 0, 0)))
if light_node:
# 设置名称
light_node.setName(name)
# 恢复其他属性
light_data = node_data.get('light_data', {})
rp_light = light_node.getPythonTag("rp_light_object")
if rp_light and light_data:
if 'energy' in light_data:
rp_light.energy = light_data['energy']
if 'radius' in light_data:
rp_light.radius = light_data['radius']
if 'fov' in light_data and hasattr(rp_light, 'fov'):
rp_light.fov = light_data['fov']
if 'inner_radius' in light_data and hasattr(rp_light, 'inner_radius'):
rp_light.inner_radius = light_data['inner_radius']
if 'casts_shadows' in light_data and hasattr(rp_light, 'casts_shadows'):
rp_light.casts_shadows = light_data['casts_shadows']
if 'shadow_map_resolution' in light_data and hasattr(rp_light, 'shadow_map_resolution'):
rp_light.shadow_map_resolution = light_data['shadow_map_resolution']
# 恢复其他标签
for tag_key, tag_value in node_data.get('tags', {}).items():
if tag_key not in ['name', 'light_type']:
light_node.setTag(tag_key, str(tag_value))
return light_node
except Exception as e:
print(f"重建光源失败: {e}")
return None
def createSpotLight(self, pos=(0, 0, 5)):
"""创建聚光灯
Args:
pos (tuple): 光源位置 (x, y, z)
Returns:
NodePath: 创建的聚光灯节点
"""
try:
# 检查是否使用RenderPipeline
if hasattr(self.world, 'render_pipeline') and self.world.render_pipeline:
from RenderPipelineFile.rpcore import SpotLight
from core.render_pipeline_utils import get_render_pipeline
# 创建RenderPipeline聚光灯
from panda3d.core import Vec3
spotlight = SpotLight()
spotlight.direction = Vec3(0, 0, -1) # 向下照射
spotlight.fov = 70 # 聚光角度
spotlight.set_color_from_temperature(6500) # 日光色温
spotlight.energy = 5000 # 光照强度
spotlight.radius = 1000 # 光照范围
spotlight.casts_shadows = True # 启用阴影
spotlight.shadow_map_resolution = 256 # 阴影分辨率
spotlight.setPos(pos)
# 添加到RenderPipeline
render_pipeline = get_render_pipeline()
if render_pipeline:
render_pipeline.add_light(spotlight)
print(f"✓ RenderPipeline聚光灯创建成功位置: {pos}")
# 创建包装节点用于场景树显示
light_name = f"Spotlight_{len(self.Spotlight)}"
spotlight_node = self.world.render.attachNewNode(light_name)
spotlight_node.setPos(*pos)
spotlight_node.setTag("light_type", "spot_light")
spotlight_node.setTag("is_scene_element", "1")
spotlight_node.setTag("tree_item_type", "LIGHT_NODE")
spotlight_node.setTag("light_energy", str(getattr(spotlight, "energy", 5000)))
spotlight_node.setTag("created_by_user", "1")
spotlight_node.setTag("element_type", "spotlight")
spotlight_node.setPythonTag("rp_light_object", spotlight)
self.Spotlight.append(spotlight_node)
return spotlight_node
else:
print("✗ 无法获取RenderPipeline实例")
return None
else:
# 使用标准Panda3D光源
from panda3d.core import Spotlight, PerspectiveLens
# 创建聚光灯
spotlight = Spotlight('spotlight')
spotlight.setColor((1, 1, 1, 1)) # 白色光
spotlight.setLens(PerspectiveLens())
# 创建光源节点
spotlight_node = self.world.render.attachNewNode(spotlight)
spotlight_node.setPos(pos)
spotlight_node.setTag("light_type", "spot_light")
spotlight_node.setTag("is_scene_element", "1")
spotlight_node.setTag("tree_item_type", "LIGHT_NODE")
spotlight_node.setTag("created_by_user", "1")
spotlight_node.setTag("element_type", "spotlight")
# 设置聚光灯方向(向下照射)
spotlight_node.lookAt(pos[0], pos[1], pos[2] - 5) # 向下看5个单位
# 设置聚光灯范围
spotlight.setExponent(1.0) # 聚光指数
spotlight.setAttenuation((1, 0.1, 0.01)) # 衰减
# 添加到光源列表
self.Spotlight.append(spotlight_node)
# 启用光源
self.world.render.setLight(spotlight_node)
# 启用阴影
if hasattr(spotlight, 'setShadowCaster'):
spotlight.setShadowCaster(True)
print(f"✓ 标准聚光灯创建成功,位置: {pos}")
return spotlight_node
except Exception as e:
print(f"✗ 创建聚光灯失败: {e}")
return None
def createPointLight(self, pos=(0, 0, 5)):
"""创建点光源
Args:
pos (tuple): 光源位置 (x, y, z)
Returns:
NodePath: 创建的点光源节点
"""
try:
# 检查是否使用RenderPipeline
if hasattr(self.world, 'render_pipeline') and self.world.render_pipeline:
from RenderPipelineFile.rpcore import PointLight
from core.render_pipeline_utils import get_render_pipeline
# 创建RenderPipeline点光源
pointlight = PointLight()
pointlight.set_color_from_temperature(6500) # 日光色温
pointlight.energy = 3000 # 光照强度
pointlight.radius = 1000 # 光照范围
pointlight.casts_shadows = True # 启用阴影
pointlight.shadow_map_resolution = 256 # 阴影分辨率
pointlight.setPos(pos)
# 添加到RenderPipeline
render_pipeline = get_render_pipeline()
if render_pipeline:
render_pipeline.add_light(pointlight)
print(f"✓ RenderPipeline点光源创建成功位置: {pos}")
# 创建包装节点用于场景树显示
light_name = f"Pointlight_{len(self.Pointlight)}"
pointlight_node = self.world.render.attachNewNode(light_name)
pointlight_node.setPos(*pos)
pointlight_node.setTag("light_type", "point_light")
pointlight_node.setTag("is_scene_element", "1")
pointlight_node.setTag("tree_item_type", "LIGHT_NODE")
pointlight_node.setTag("light_energy", str(getattr(pointlight, "energy", 3000)))
pointlight_node.setTag("created_by_user", "1")
pointlight_node.setTag("element_type", "pointlight")
pointlight_node.setPythonTag("rp_light_object", pointlight)
self.Pointlight.append(pointlight_node)
return pointlight_node
else:
print("✗ 无法获取RenderPipeline实例")
return None
else:
# 使用标准Panda3D光源
from panda3d.core import PointLight
# 创建点光源
pointlight = PointLight('pointlight')
pointlight.setColor((1, 1, 1, 1)) # 白色光
pointlight.setAttenuation((1, 0.1, 0.01)) # 衰减设置
# 创建光源节点
pointlight_node = self.world.render.attachNewNode(pointlight)
pointlight_node.setPos(pos)
pointlight_node.setTag("light_type", "point_light")
pointlight_node.setTag("is_scene_element", "1")
pointlight_node.setTag("tree_item_type", "LIGHT_NODE")
pointlight_node.setTag("created_by_user", "1")
pointlight_node.setTag("element_type", "pointlight")
# 添加到光源列表
self.Pointlight.append(pointlight_node)
# 启用光源
self.world.render.setLight(pointlight_node)
# 启用阴影
if hasattr(pointlight, 'setShadowCaster'):
pointlight.setShadowCaster(True)
print(f"✓ 标准点光源创建成功,位置: {pos}")
return pointlight_node
except Exception as e:
print(f"✗ 创建点光源失败: {e}")
return None