460 lines
19 KiB
Python
460 lines
19 KiB
Python
"""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)
|
||
spotlight_node.setPythonTag("engine_light_registered", True)
|
||
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.setPythonTag("engine_light_registered", True)
|
||
|
||
# 设置聚光灯方向(向下照射)
|
||
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)
|
||
pointlight_node.setPythonTag("engine_light_registered", True)
|
||
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")
|
||
pointlight_node.setPythonTag("engine_light_registered", True)
|
||
|
||
# 添加到光源列表
|
||
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
|