Merge remote-tracking branch 'refs/remotes/origin/ch' into addRender

# Conflicts:
#	RenderPipelineFile/config/daytime.yaml
This commit is contained in:
Hector 2025-11-03 09:39:37 +08:00
commit 0c25623606
5 changed files with 255 additions and 64 deletions

2
.idea/EG.iml generated
View File

@ -5,7 +5,7 @@
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (EG)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.10 (eg)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">

View File

@ -5,6 +5,9 @@ import sys
project_root = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, project_root)
# 设置工作目录为项目根目录
os.chdir(project_root)
# 添加 RenderPipeline 到路径(注意路径名称应与实际目录一致)
render_pipeline_path = os.path.join(project_root, "RenderPipeline")
sys.path.insert(0, render_pipeline_path)

View File

@ -11,5 +11,8 @@
"enable_ssr": false,
"shadow_quality": "medium",
"ao_quality": "low"
}
},
"anti_aliasing": "4x",
"refresh_rate": "90Hz",
"async_reprojection": true
}

95
tools/open_source_rate.py Normal file
View File

@ -0,0 +1,95 @@
import os
from pathlib import Path
THIRD_PARTY_DIR_NAMES = {
'node_modules', 'vendor', 'third_party', 'third-party', 'extern', 'external', 'deps',
'Cesium', 'Cesium-1.132', 'dist', 'build'
}
CODE_EXTENSIONS = {
'.py', '.js', '.ts', '.tsx', '.jsx', '.css', '.scss', '.html', '.c', '.h', '.cpp', '.hpp',
'.cc', '.hh', '.m', '.mm', '.java', '.go', '.rs', '.cs', '.vue', '.svelte'
}
SKIP_DIR_NAMES = {
'.git', '.hg', '.svn', '__pycache__', '.mypy_cache', '.pytest_cache', '.idea', '.vscode',
'.venv', 'venv', 'env', '.tox', '.cache', 'Resources', 'icons', 'tex', 'terminal'
}
MAX_FILE_SIZE_BYTES = 2 * 1024 * 1024 # 2 MiB
def is_third_party(path: Path) -> bool:
for part in path.parts:
# normalize case on Windows
name = part.lower()
if name in {n.lower() for n in THIRD_PARTY_DIR_NAMES}:
return True
return False
def should_skip_dir(dirname: str) -> bool:
return dirname.lower() in {n.lower() for n in SKIP_DIR_NAMES}
def is_code_file(path: Path) -> bool:
return path.suffix.lower() in CODE_EXTENSIONS
def count_lines(path: Path) -> int:
try:
if path.stat().st_size > MAX_FILE_SIZE_BYTES:
return 0
# Try text read with universal newlines, fallback to binary
try:
with path.open('r', encoding='utf-8', errors='ignore') as f:
return sum(1 for _ in f)
except Exception:
with path.open('rb') as f:
return f.read().count(b'\n')
except Exception:
return 0
def main(root: Path) -> None:
third_party_loc = 0
first_party_loc = 0
third_party_files = 0
first_party_files = 0
for dirpath, dirnames, filenames in os.walk(root):
# prune directories
dirnames[:] = [d for d in dirnames if not should_skip_dir(d)]
current = Path(dirpath)
current_is_third = is_third_party(current)
for fn in filenames:
p = current / fn
if not is_code_file(p):
continue
loc = count_lines(p)
if current_is_third:
third_party_loc += loc
third_party_files += 1
else:
first_party_loc += loc
first_party_files += 1
total_loc = first_party_loc + third_party_loc
open_source_rate = (third_party_loc / total_loc) * 100 if total_loc else 0.0
print('Open-Source Rate (by LOC): {:.2f}%'.format(open_source_rate))
print('\nBreakdown:')
print(' First-party LOC : {} ({} files)'.format(first_party_loc, first_party_files))
print(' Third-party LOC : {} ({} files)'.format(third_party_loc, third_party_files))
print(' Total LOC : {}'.format(total_loc))
print('\nNotes:')
print(' - Third-party directories are heuristically detected by common names: {}'.format(', '.join(sorted(THIRD_PARTY_DIR_NAMES))))
print(' - Static asset directories are skipped: {}'.format(', '.join(sorted(SKIP_DIR_NAMES))))
print(' - Counted code extensions: {}'.format(', '.join(sorted(CODE_EXTENSIONS))))
if __name__ == '__main__':
main(Path('.').resolve())

View File

@ -9790,6 +9790,12 @@ except Exception as e:
collision_group.setLayout(collision_layout)
self._propertyLayout.addWidget(collision_group)
# 同步一次状态,确保主按钮与可见性按钮齐全
try:
self._updateCollisionPanelState(model)
except Exception:
pass
except Exception as e:
print(f"创建碰撞面板失败: {e}")
import traceback
@ -10144,8 +10150,9 @@ except Exception as e:
collision_np.show()
print(f"显示碰撞:{model.getName()}")
# 立即更新按钮状态
# 立即更新按钮状态,并同步更新面板(确保缺失主按钮时补建)
self._updateCollisionVisibilityButton(model)
self._updateCollisionPanelState(model)
except Exception as e:
print(f"切换碰撞可见性失败: {e}")
@ -10353,26 +10360,18 @@ except Exception as e:
has_collision = self._hasCollision(model)
print(f"模型 {model.getName()} 是否有碰撞体: {has_collision}-------------------------------------------------")
# 更新状态徽章(使用固定宽度)
if has_collision:
new_badge = self.createFixedStatusBadge("已启用", "green")
else:
new_badge = self.createFixedStatusBadge("未启用", "red")
# 替换旧的徽章
old_badge = self.collision_status_badge
parent_layout = old_badge.parent().layout()
if parent_layout:
# 找到旧徽章在布局中的位置
for i in range(parent_layout.count()):
item = parent_layout.itemAt(i)
if item and item.widget() == old_badge:
# 移除旧徽章并添加新徽章
parent_layout.removeWidget(old_badge)
old_badge.deleteLater()
parent_layout.addWidget(new_badge, 0, 0, 1, 1) # 状态徽章在第0行第1列
self.collision_status_badge = new_badge
break
# 更新状态徽章(直接修改现有控件,避免布局冲突)
if hasattr(self, 'collision_status_badge') and self.collision_status_badge:
if has_collision:
self.collision_status_badge.setText("已启用")
# 使用固定宽度的绿色样式,保持尺寸一致
self.collision_status_badge.setStyleSheet(self.badge_style_green_fixed)
else:
self.collision_status_badge.setText("未启用")
# 使用固定宽度的红色样式,保持尺寸一致
self.collision_status_badge.setStyleSheet(self.badge_style_red_fixed)
# 触发重绘,确保立即可见
self.collision_status_badge.update()
if has_collision:
# 有碰撞:显示移除按钮,下拉框变为只读并显示当前类型
@ -10388,6 +10387,18 @@ except Exception as e:
except:
pass
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
else:
# 若不存在主按钮,则创建“移除碰撞”按钮并加入布局
try:
self.collision_button = self.createModernButton("移除碰撞")
self.collision_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.collision_button.setStyleSheet(self._collision_button_style())
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
if hasattr(self, 'collision_layout') and self.collision_layout is not None:
row = self.collision_layout.rowCount()
self.collision_layout.addWidget(self.collision_button, row, 0, 1, 4)
except Exception as _e:
print(f"创建移除碰撞按钮失败: {_e}")
# 获取并显示当前碰撞类型,设置为只读
current_shape = self._getCurrentCollisionShape(model)
@ -10407,6 +10418,13 @@ except Exception as e:
self.collision_visibility_button.setVisible(True)
self._updateCollisionVisibilityButton(model)
# 确保按钮顺序:可见性按钮在上,主按钮在下
if hasattr(self, 'collision_layout'):
try:
self._repositionButtons(self.collision_layout.rowCount())
except Exception:
pass
print(f"碰撞面板状态更新:有碰撞 - {current_shape}")
else:
@ -10422,6 +10440,18 @@ except Exception as e:
except:
pass
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
else:
# 若不存在主按钮,则创建“添加碰撞”按钮并加入布局
try:
self.collision_button = self.createModernButton("添加碰撞")
self.collision_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.collision_button.setStyleSheet(self._collision_button_style())
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
if hasattr(self, 'collision_layout') and self.collision_layout is not None:
row = self.collision_layout.rowCount()
self.collision_layout.addWidget(self.collision_button, row, 0, 1, 4)
except Exception as _e:
print(f"创建添加碰撞按钮失败: {_e}")
# 恢复为可编辑状态
self.collision_shape_combo.setEnabled(True)
@ -10435,6 +10465,13 @@ except Exception as e:
if hasattr(self, 'collision_visibility_button'):
self.collision_visibility_button.setVisible(False)
# 确保按钮顺序:主按钮位于底部
if hasattr(self, 'collision_layout'):
try:
self._repositionButtons(self.collision_layout.rowCount())
except Exception:
pass
print(f"碰撞面板状态更新:无碰撞 - 可编辑")
except Exception as e:
@ -11097,13 +11134,24 @@ except Exception as e:
layout = self.collision_layout
is_collision_visible = self._isCollisionVisible(model)
# 找到合适的行位置
# 放在当前最后一行
current_row = layout.rowCount()
self.collision_visibility_button = QPushButton("隐藏碰撞" if is_collision_visible else "显示碰撞")
self.collision_visibility_button.setStyleSheet(self._collision_button_style())
self.collision_visibility_button.clicked.connect(lambda: self._toggleCollisionVisibility(model))
layout.addWidget(self.collision_visibility_button, current_row - 1, 0, 1, 4)
layout.addWidget(self.collision_visibility_button, current_row, 0, 1, 4)
# 确保存在主按钮(有碰撞时应显示移除碰撞)
if self._hasCollision(model) and not hasattr(self, 'collision_button'):
try:
self.collision_button = self.createModernButton("移除碰撞")
self.collision_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.collision_button.setStyleSheet(self._collision_button_style())
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
layout.addWidget(self.collision_button, current_row + 1, 0, 1, 4)
except Exception as _e:
print(f"在可见性按钮后创建移除碰撞按钮失败: {_e}")
except Exception as e:
print(f"添加可见性按钮失败: {e}")
@ -11114,22 +11162,39 @@ except Exception as e:
if hasattr(self, 'collision_layout'):
layout = self.collision_layout
# 移动可见性按钮
if hasattr(self, 'collision_visibility_button'):
layout.addWidget(self.collision_visibility_button, new_row, 0, 1, 4)
new_row += 1
def _remove_if_present(w):
try:
if not w:
return
# 从布局中移除该控件(如果已存在)
for i in range(layout.count()):
item = layout.itemAt(i)
if item and item.widget() is w:
layout.removeWidget(w)
break
except Exception:
pass
# 移动主按钮
if hasattr(self, 'collision_button'):
layout.addWidget(self.collision_button, new_row, 0, 1, 4)
# 计算底部行
bottom_row = layout.rowCount()
# 按固定顺序重新放置:先可见性按钮,再主按钮
if hasattr(self, 'collision_visibility_button') and self.collision_visibility_button:
_remove_if_present(self.collision_visibility_button)
layout.addWidget(self.collision_visibility_button, bottom_row, 0, 1, 4)
bottom_row += 1
if hasattr(self, 'collision_button') and self.collision_button:
_remove_if_present(self.collision_button)
layout.addWidget(self.collision_button, bottom_row, 0, 1, 4)
except Exception as e:
print(f"重新定位按钮失败: {e}")
def _hideCollisionParameterControls(self):
"""隐藏碰撞参数控件(保留按钮)"""
"""隐藏并移除碰撞参数控件与其所在的行(保留状态/形状/按钮"""
try:
# 清理属性引用,但保留按钮
# 1) 先清理对象属性引用,避免残留信号
param_attrs = [
'collision_pos_x', 'collision_pos_y', 'collision_pos_z',
'collision_radius',
@ -11137,47 +11202,72 @@ except Exception as e:
'collision_capsule_radius', 'collision_capsule_height',
'collision_normal_x', 'collision_normal_y', 'collision_normal_z'
]
# 隐藏并删除参数控件
for attr in param_attrs:
if hasattr(self, attr):
widget = getattr(self, attr)
if widget:
widget.setVisible(False)
widget.setParent(None)
widget.deleteLater()
try:
if widget:
widget.setParent(None)
widget.deleteLater()
except Exception:
pass
delattr(self, attr)
# 同时清理可能的标签控件
if hasattr(self, 'collision_layout'):
# 2) 深度移除布局中第2行索引>=2之后的所有参数相关项保留按钮
if hasattr(self, 'collision_layout') and self.collision_layout is not None:
layout = self.collision_layout
# 收集需要移除的控件(不包括基本控件和按钮)
widgets_to_remove = []
def _remove_layout_recursive(q_layout):
try:
while q_layout.count():
child = q_layout.takeAt(0)
if child.widget():
w = child.widget()
w.setParent(None)
w.deleteLater()
elif child.layout():
_remove_layout_recursive(child.layout())
except Exception:
pass
for i in range(layout.rowCount()):
if i >= 2: # 从第3行开始检查
for j in range(layout.columnCount()):
item = layout.itemAtPosition(i, j)
if item:
widget = item.widget()
if widget and hasattr(widget, 'text'):
# 检查是否是参数相关的标签
text = widget.text()
if any(keyword in text for keyword in
['位置偏移', 'X:', 'Y:', 'Z:', '半径:', '尺寸:', '宽度:', '长度:', '高度:',
'法向量:', 'Nx:', 'Ny:', 'Nz:']):
widgets_to_remove.append(widget)
row_count = layout.rowCount()
col_count = layout.columnCount()
# 从参数区域开始清理行索引2及以后但跳过我们要保留的按钮
for i in range(2, row_count):
for j in range(0, col_count):
item = layout.itemAtPosition(i, j)
if not item:
continue
# 若是按钮,且是保留的按钮,则跳过
w = item.widget()
if w is not None:
try:
if (hasattr(self, 'collision_button') and w == self.collision_button) or (hasattr(self, 'collision_visibility_button') and w == self.collision_visibility_button):
continue
except Exception:
pass
layout.removeWidget(w)
w.setParent(None)
w.deleteLater()
elif item.layout():
# 移除嵌套布局(包含标签与输入框)
nested = item.layout()
_remove_layout_recursive(nested)
layout.removeItem(nested)
# 移除参数标签
for widget in widgets_to_remove:
widget.setVisible(False)
widget.setParent(None)
widget.deleteLater()
# 尝试把保留的按钮移动到参数区域第一行行2下方保持整洁
try:
next_row = 2
if hasattr(self, 'collision_visibility_button'):
self.collision_visibility_button.setVisible(False)
if hasattr(self, 'collision_button') and self.collision_button is not None:
layout.addWidget(self.collision_button, next_row, 0, 1, 4)
except Exception:
pass
print("隐藏碰撞参数控件完成(保留按钮)")
print("隐藏碰撞参数控件完成(保留状态、形状与按钮)")
except Exception as e:
print(f"隐藏碰撞参数控件失败: {e}")
import traceback
traceback.print_exc()
traceback.print_exc()