渲染
ESEngine 使用基于组件的渲染系统。在场景编辑器中为实体添加渲染组件,C++ 后端自动处理绘制。
相机
需要 Camera 组件才能看到内容。编辑器的默认场景已包含一个。
Camera 属性
| 属性 | 类型 | 说明 |
|---|---|---|
projectionType | number | 0 = 透视,1 = 正交 |
fov | number | 视角角度(仅透视) |
orthoSize | number | 半高世界单位(仅正交) |
nearPlane | number | 近裁剪面 |
farPlane | number | 远裁剪面 |
isActive | boolean | 是否用于渲染 |
aspectRatio | number | 相机宽高比 |
priority | number | 渲染顺序 — 低优先级先渲染,高优先级覆盖在上 |
viewportX | number | 视口左边缘(0–1)。默认:0 |
viewportY | number | 视口底边缘(0–1)。默认:0 |
viewportW | number | 视口宽度(0–1)。默认:1 |
viewportH | number | 视口高度(0–1)。默认:1 |
clearFlags | number | 缓冲区清除模式:0=无, 1=颜色, 2=深度, 3=两者 |
showFrustum | boolean | 在编辑器中显示相机视锥线框 |
正交相机
2D 游戏最佳选择。orthoSize 决定可见的世界范围。在检查器中将 projectionType 设为 1。
Canvas 集成
要进行屏幕适配和分辨率缩放,在相机实体上附加 Canvas 组件。详见 Canvas 与分辨率。
移动相机
查询相机实体并修改其 transform:
import { defineSystem, addSystem, Res, Input, Query, Mut, LocalTransform, Camera } from 'esengine';
addSystem(defineSystem( [Res(Input), Query(Mut(LocalTransform), Camera)], (input, query) => { for (const [entity, transform, camera] of query) { if (input.isKeyDown('ArrowLeft')) { transform.position.x -= 5; } if (input.isKeyDown('ArrowRight')) { transform.position.x += 5; } } }));多相机渲染
多个相机可以同时渲染到不同的视口区域。每个相机有独立的视口 (viewportX/Y/W/H) 和 clearFlags。
主相机 + 小地图:
创建两个 Camera 实体:
- 主相机:视口
(0, 0, 1, 1),priority: 0 - 小地图相机:视口
(0.75, 0.75, 0.25, 0.25),priority: 1,clearFlags: 3
小地图在右上角渲染,覆盖在主视图之上。
分屏:
- 玩家 1:视口
(0, 0, 0.5, 1),priority: 0 - 玩家 2:视口
(0.5, 0, 0.5, 1),priority: 0
两个相机并排渲染。相同优先级的相机按实体顺序渲染。
Transform
每个可见实体都需要 LocalTransform。在场景编辑器中添加并在检查器中配置位置、旋转和缩放。
旋转
旋转使用四元数。绕 Z 轴的 2D 旋转:
import { defineSystem, addSystem, Res, Time, Query, Mut, LocalTransform, Sprite } from 'esengine';
addSystem(defineSystem( [Res(Time), Query(Mut(LocalTransform), Sprite)], (time, query) => { for (const [entity, transform, sprite] of query) { const angle = time.elapsed; const halfAngle = angle / 2; transform.rotation = { w: Math.cos(halfAngle), x: 0, y: 0, z: Math.sin(halfAngle) }; } }));缩放
transform.scale = { x: 2, y: 2, z: 1 }; // 放大两倍transform.scale = { x: -1, y: 1, z: 1 }; // 水平翻转渲染顺序
精灵按以下顺序绘制:
- Z 坐标 (
transform.position.z) — Z 值越小越先绘制(在后面) - Layer (
sprite.layer) — layer 值越大越在上面
在检查器中设置或运行时修改。
渲染统计
使用 Renderer.getStats() 获取每帧渲染统计数据,可用于性能分析和调试面板:
import { Renderer, type RenderStats } from 'esengine';
const stats: RenderStats = Renderer.getStats();console.log(`Draw calls: ${stats.drawCalls}, Triangles: ${stats.triangles}`);| 字段 | 类型 | 说明 |
|---|---|---|
drawCalls | number | 本帧 WebGL draw call 总数 |
triangles | number | 渲染的三角形总数 |
sprites | number | 绘制的精灵数 |
text | number | 绘制的文本元素数 |
spine | number | 绘制的 Spine 骨骼数 |
meshes | number | 绘制的自定义网格数 |
culled | number | 被裁剪的对象数(未绘制) |
渲染阶段
渲染管线分为多个阶段,按顺序执行。每个阶段绘制一类对象:
| 阶段 | 值 | 说明 |
|---|---|---|
Background | 0 | 背景层(天空盒、背景) |
Opaque | 1 | 不透明几何体(无透明度) |
Transparent | 2 | 透明/Alpha 混合对象 |
Overlay | 3 | UI 和覆盖元素(绘制在最上层) |
使用自定义绘制时,指定 RenderStage 来控制绘制命令相对于内置渲染的执行时机:
import { Draw, RenderStage } from 'esengine';
Draw.bindStage(RenderStage.Overlay);Draw.rect(0, 0, 100, 50, { r: 0, g: 0, b: 0, a: 0.5 });