Files
esengine/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/NodeRenderSystem.ts
YHH bb19f752a1 优化性能结构/延迟加载
新增测试代码用于测试性能
2025-07-02 00:13:29 +08:00

475 lines
16 KiB
TypeScript
Raw 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.
import { EntitySystem, Entity, Matcher, Time } from '@esengine/ecs-framework';
import { NodeComponent, Transform, Renderer } from '../components';
import { Node, Vec3, Color } from 'cc';
/**
* 节点渲染系统 - 处理NodeComponent和Cocos Creator节点的同步
*/
export class NodeRenderSystem extends EntitySystem {
/** 渲染统计 */
private renderStats = {
totalNodes: 0,
visibleNodes: 0,
renderCalls: 0,
averageRenderTime: 0,
totalRenderTime: 0,
frameCount: 0
};
/** 节点池 */
private nodePool: Node[] = [];
/** 性能监控 */
private performanceMonitor = {
frameStartTime: 0,
renderTimeHistory: [] as number[],
cullCount: 0,
frustumCullCount: 0
};
constructor() {
// 处理具有NodeComponent的实体
super(Matcher.empty().all(NodeComponent));
}
/**
* 处理所有实体
*/
protected process(entities: Entity[]): void {
this.performanceMonitor.frameStartTime = performance.now();
this.renderStats.totalNodes = entities.length;
this.renderStats.visibleNodes = 0;
this.renderStats.renderCalls = 0;
for (const entity of entities) {
this.processEntity(entity);
}
// 处理节点层次结构
this.updateNodeHierarchy(entities);
// 更新性能统计
this.updatePerformanceStats();
// 清理过期的性能缓存
this.cleanupPerformanceCache(entities);
}
/**
* 处理单个实体
*/
private processEntity(entity: Entity): void {
const nodeComponent = entity.getComponent(NodeComponent);
const transform = entity.getComponent(Transform);
const renderer = entity.getComponent(Renderer);
if (!nodeComponent) return;
const renderStartTime = performance.now();
// 确保有对应的Cocos Creator节点
this.ensureNode(nodeComponent, entity);
// 同步Transform数据
if (transform && nodeComponent.node) {
this.syncTransform(nodeComponent, transform);
}
// 同步渲染数据
if (renderer && nodeComponent.node) {
this.syncRenderer(nodeComponent, renderer);
}
// 更新节点配置
this.updateNodeConfig(nodeComponent);
// 执行视锥体剔除
const isVisible = this.performCulling(nodeComponent);
if (isVisible) {
this.renderStats.visibleNodes++;
this.performRender(nodeComponent);
}
// 更新性能统计
const renderTime = performance.now() - renderStartTime;
nodeComponent.updatePerformance(renderTime);
this.renderStats.renderCalls++;
this.renderStats.totalRenderTime += renderTime;
}
/**
* 确保节点存在
*/
private ensureNode(nodeComponent: NodeComponent, entity: Entity): void {
if (!nodeComponent.node) {
// 从对象池中获取节点或创建新节点
nodeComponent.node = this.getNodeFromPool() || new Node(nodeComponent.nodeConfig.name);
// 初始化节点
this.initializeNode(nodeComponent.node, nodeComponent, entity);
}
}
/**
* 从对象池获取节点
*/
private getNodeFromPool(): Node | null {
return this.nodePool.pop() || null;
}
/**
* 初始化节点
*/
private initializeNode(node: Node, nodeComponent: NodeComponent, entity: Entity): void {
const config = nodeComponent.nodeConfig;
// 设置基本属性
node.name = config.name;
node.layer = config.layer;
node.active = config.renderData.visible;
// 设置变换
node.setPosition(config.transformData.position);
node.setRotationFromEuler(config.transformData.rotation);
node.setScale(config.transformData.scale);
// 设置渲染属性
const opacity = Math.floor(config.renderData.opacity * 255);
// 这里可以设置更多Cocos Creator特定的属性
// 添加用户数据
config.userData.entityId = entity.id;
config.userData.componentId = nodeComponent.id;
}
/**
* 同步Transform数据
*/
private syncTransform(nodeComponent: NodeComponent, transform: Transform): void {
const node = nodeComponent.node!;
const config = nodeComponent.nodeConfig;
// 更新配置中的变换数据
config.transformData.position.set(transform.position);
config.transformData.rotation.set(transform.rotation);
config.transformData.scale.set(transform.scale);
// 同步到Cocos Creator节点
node.setPosition(transform.position);
node.setRotationFromEuler(transform.rotation);
node.setScale(transform.scale);
// 更新缓存数据
nodeComponent.complexData.cache.textureCache.set('lastPosition', transform.position.clone());
}
/**
* 同步渲染数据
*/
private syncRenderer(nodeComponent: NodeComponent, renderer: Renderer): void {
const node = nodeComponent.node!;
const config = nodeComponent.nodeConfig;
// 更新配置中的渲染数据
config.renderData.color.set(renderer.color);
config.renderData.opacity = renderer.alpha;
config.renderData.visible = renderer.visible && renderer.alpha > 0;
// 同步到Cocos Creator节点
node.active = config.renderData.visible;
// 更新材质缓存
nodeComponent.complexData.cache.materialCache.set('currentColor', renderer.color.clone());
nodeComponent.complexData.cache.materialCache.set('alpha', renderer.alpha);
}
/**
* 更新节点配置
*/
private updateNodeConfig(nodeComponent: NodeComponent): void {
const config = nodeComponent.nodeConfig;
const currentTime = Date.now();
// 更新统计信息
nodeComponent.complexData.statistics.frameCount++;
nodeComponent.complexData.statistics.lastUpdateTime = currentTime;
// 更新用户数据
config.userData.lastFrameUpdate = currentTime;
config.userData.frameCount = nodeComponent.complexData.statistics.frameCount;
// 动态调整配置
if (Math.random() < 0.01) { // 1% 概率调整
config.renderData.opacity *= (0.95 + Math.random() * 0.1); // 轻微透明度变化
config.renderData.opacity = Math.max(0.1, Math.min(1.0, config.renderData.opacity));
}
}
/**
* 执行视锥体剔除
*/
private performCulling(nodeComponent: NodeComponent): boolean {
if (!nodeComponent.node) {
return false;
}
const config = nodeComponent.nodeConfig;
// 简单的可见性检查
if (!config.renderData.visible || config.renderData.opacity <= 0) {
this.performanceMonitor.cullCount++;
return false;
}
// 距离剔除
const position = config.transformData.position;
const distance = position.length();
if (distance > 1000) { // 超过1000单位距离的对象被剔除
this.performanceMonitor.frustumCullCount++;
return false;
}
// 层级剔除
if (config.layer < 0) {
this.performanceMonitor.cullCount++;
return false;
}
return true;
}
/**
* 执行渲染
*/
private performRender(nodeComponent: NodeComponent): void {
if (!nodeComponent.node) return;
const renderStartTime = performance.now();
// 模拟复杂的渲染过程
this.simulateRenderingWork(nodeComponent);
// 更新子节点
this.updateChildNodes(nodeComponent);
// 更新着色器缓存
this.updateShaderCache(nodeComponent);
const renderTime = performance.now() - renderStartTime;
// 更新性能统计
const perf = nodeComponent.complexData.statistics.performance;
perf.renderHistory.push(renderTime);
if (perf.renderHistory.length > 100) {
perf.renderHistory.shift();
}
perf.avgRenderTime = perf.renderHistory.reduce((a, b) => a + b, 0) / perf.renderHistory.length;
perf.maxRenderTime = Math.max(perf.maxRenderTime, renderTime);
}
/**
* 模拟渲染工作
*/
private simulateRenderingWork(nodeComponent: NodeComponent): void {
const complexity = nodeComponent.complexData.cache.materialCache.size +
nodeComponent.complexData.cache.textureCache.size;
// 模拟基于复杂度的计算工作
let iterations = Math.min(complexity * 10, 1000);
let result = 0;
for (let i = 0; i < iterations; i++) {
result += Math.sin(i * 0.001) * Math.cos(i * 0.002);
}
// 存储计算结果到缓存
nodeComponent.complexData.cache.shaderCache.set('computeResult', result);
}
/**
* 更新子节点
*/
private updateChildNodes(nodeComponent: NodeComponent): void {
if (nodeComponent.children.length === 0) return;
const parentNode = nodeComponent.node!;
// 同步子节点
for (let i = 0; i < nodeComponent.children.length; i++) {
const childNode = nodeComponent.children[i];
if (childNode && childNode.parent !== parentNode) {
parentNode.addChild(childNode);
}
}
// 更新层次结构数据
nodeComponent.complexData.hierarchy.siblingIndex = parentNode.getSiblingIndex();
// 更新子组件的层次深度(需要通过实体管理器查找)
// 这里省略了复杂的查找逻辑,避免循环引用
if (nodeComponent.nodeConfig.childIds.length > 0) {
// 实际项目中应该通过实体管理器查找子实体并更新深度
// 为了示例简化,我们只更新自己的深度
nodeComponent.complexData.hierarchy.depth = Math.max(0, nodeComponent.complexData.hierarchy.depth);
}
}
/**
* 更新着色器缓存
*/
private updateShaderCache(nodeComponent: NodeComponent): void {
const shaderCache = nodeComponent.complexData.cache.shaderCache;
// 模拟着色器参数更新
const currentTime = Date.now();
shaderCache.set('time', currentTime);
shaderCache.set('frameCount', nodeComponent.complexData.statistics.frameCount);
// 清理过期的着色器缓存
if (shaderCache.size > 50) {
const keys = Array.from(shaderCache.keys());
const oldestKey = keys[0];
shaderCache.delete(oldestKey);
}
}
/**
* 更新节点层次结构
*/
private updateNodeHierarchy(entities: Entity[]): void {
// 构建层次结构映射
const nodeMap = new Map<number, NodeComponent>();
entities.forEach(entity => {
const nodeComponent = entity.getComponent(NodeComponent);
if (nodeComponent) {
nodeMap.set(entity.id, nodeComponent);
}
});
// 更新层次关系使用ID避免循环引用
nodeMap.forEach((nodeComponent, entityId) => {
// 更新根节点ID
if (!nodeComponent.complexData.hierarchy.parentId) {
nodeComponent.complexData.hierarchy.rootId = entityId;
} else {
// 查找根节点ID简化版本避免深度遍历
let currentParentId = nodeComponent.complexData.hierarchy.parentId;
let depth = 0;
// 限制深度以避免无限循环
while (currentParentId && depth < 10) {
const parentNode = nodeMap.get(currentParentId);
if (parentNode && parentNode.complexData.hierarchy.parentId) {
currentParentId = parentNode.complexData.hierarchy.parentId;
depth++;
} else {
break;
}
}
nodeComponent.complexData.hierarchy.rootId = currentParentId || entityId;
}
});
}
/**
* 更新性能统计
*/
private updatePerformanceStats(): void {
const frameTime = performance.now() - this.performanceMonitor.frameStartTime;
this.performanceMonitor.renderTimeHistory.push(frameTime);
if (this.performanceMonitor.renderTimeHistory.length > 60) {
this.performanceMonitor.renderTimeHistory.shift();
}
this.renderStats.frameCount++;
if (this.renderStats.renderCalls > 0) {
this.renderStats.averageRenderTime = this.renderStats.totalRenderTime / this.renderStats.renderCalls;
}
}
/**
* 清理性能缓存
*/
private cleanupPerformanceCache(entities: Entity[]): void {
entities.forEach(entity => {
const nodeComponent = entity.getComponent(NodeComponent);
if (nodeComponent) {
const caches = nodeComponent.complexData.cache;
// 清理纹理缓存
if (caches.textureCache.size > 100) {
const keys = Array.from(caches.textureCache.keys());
const toDelete = keys.slice(0, 20); // 删除最旧的20个
toDelete.forEach(key => caches.textureCache.delete(key));
}
// 清理材质缓存
if (caches.materialCache.size > 50) {
const keys = Array.from(caches.materialCache.keys());
const toDelete = keys.slice(0, 10); // 删除最旧的10个
toDelete.forEach(key => caches.materialCache.delete(key));
}
}
});
}
/**
* 回收节点到对象池
*/
public recycleNode(node: Node): void {
if (this.nodePool.length < 100) { // 限制对象池大小
node.removeFromParent();
node.destroyAllChildren();
this.nodePool.push(node);
} else {
node.destroy();
}
}
/**
* 系统初始化时调用
*/
public initialize(): void {
super.initialize();
console.log('🎨 节点渲染系统已启动');
// 预热对象池
for (let i = 0; i < 10; i++) {
this.nodePool.push(new Node(`PooledNode_${i}`));
}
}
/**
* 当实体被移除时
*/
protected onRemoved(entity: Entity): void {
const nodeComponent = entity.getComponent(NodeComponent);
if (nodeComponent && nodeComponent.node) {
this.recycleNode(nodeComponent.node);
nodeComponent.node = null;
}
}
/**
* 获取系统统计信息
*/
public getSystemStats(): any {
return {
...this.renderStats,
cullCount: this.performanceMonitor.cullCount,
frustumCullCount: this.performanceMonitor.frustumCullCount,
nodePoolSize: this.nodePool.length,
averageFrameTime: this.performanceMonitor.renderTimeHistory.length > 0
? this.performanceMonitor.renderTimeHistory.reduce((a, b) => a + b, 0) / this.performanceMonitor.renderTimeHistory.length
: 0,
systemName: 'NodeRenderSystem'
};
}
}