自定义绘制
大多数视觉是组件——精灵、瓦片地图、粒子。当它们 表达不了你要的东西——调试覆盖层、程序化形状、自定义几何——引擎把绘制层直接暴露 给你。
该用哪个 API
Section titled “该用哪个 API”| API | 模型 | 适用场景 |
|---|---|---|
Draw |
即时模式,全局——命令自动合批、每帧清空。 | 调试覆盖层、gizmo、任何每帧从头重画的东西。 |
Graphics |
保留式路径记录器——构建一次,flush() 时经 Draw 回放。 |
带路径/贝塞尔/圆弧的矢量形状,不想每帧重新细分。 |
ShapeRenderer / Mesh2D |
组件——带排序层、材质、编辑器 gizmo 的实体。 | 属于场景的形状/网格(见精灵)。 |
经验法则:视觉属于场景(参与排序、保存、可检视)就做成组件;属于某一帧 (调试、类 HUD 覆盖、程序化效果)就在回调里画。
注册一个回调,它每帧在渲染通道内执行,相机的 view-projection 已经就位——无需任何 设置,直接画:
import { registerDrawCallback, Draw } from 'esengine';
registerDrawCallback('debug-overlay', (elapsed) => { Draw.line({ x: 0, y: 0 }, { x: 100, y: 50 }, { r: 1, g: 0, b: 0, a: 1 }, 2); Draw.circleOutline({ x: 0, y: 0 }, aggroRadius, { r: 1, g: 1, b: 0, a: 0.5 });});回调画在场景之上;registerPreSceneDrawCallback 画在场景之下(其回调收到
{ width, height, elapsed })。用 unregisterDrawCallback(id) 移除。坐标都是
世界空间。
Draw API
Section titled “Draw API”Draw 是一个即时模式单例——命令自动合批、每帧清空,所以想让形状可见就每帧画:
| 方法 | 画什么 |
|---|---|
line(from, to, color, thickness?) |
一条线段(粗细单位 px,默认 1)。 |
rect(pos, size, color, filled?) / rectOutline(pos, size, color, thickness?) |
一个矩形——pos 是中心。 |
circle(center, radius, color, filled?, segments?) / circleOutline(…) |
一个圆(默认 32 段)。 |
texture(pos, size, textureHandle, tint?) |
一个贴图四边形。 |
textureRotated(pos, size, rotation, textureHandle, tint?) |
同上,带旋转(弧度)。 |
drawMesh(geometry, shader, transform) / drawMeshWithMaterial(geometry, material, transform?) |
按句柄绘制自定义网格(见下面的 Geometry API)。 |
setLayer(layer) / setDepth(depth) |
后续命令的排序。 |
setBlendMode(mode) / setDepthTest(on) |
后续命令的混合 / 深度状态。 |
getDrawCallCount() / getPrimitiveCount() |
本帧统计。 |
矢量路径:Graphics
Section titled “矢量路径:Graphics”由路径构成的形状——折线、贝塞尔、圆弧、圆角矩形——用 Graphics 记录路径,
flush() 时经 Draw 回放:
import { Graphics, registerDrawCallback } from 'esengine';
const g = new Graphics();g.lineStyle(2, { r: 1, g: 1, b: 1, a: 1 });g.beginFill({ r: 0, g: 0.5, b: 1, a: 1 });g.drawRoundRect(-50, -25, 100, 50, 8);g.endFill();g.moveTo(0, 0);g.curveTo(50, 80, 100, 0); // 二次贝塞尔
registerDrawCallback('hud-shape', () => g.flush());路径方法:moveTo / lineTo、curveTo(二次)/ cubicCurveTo、arc、
drawRect / drawRoundRect / drawCircle / drawEllipse、clear()。
lineStyle(thickness, color) 设描边;beginFill(color) / endFill() 的填充
支持矩形和圆(路径轮廓保持描边)。路径是保留的——构建一次,每帧 flush()。
自定义网格:Mesh2D
Section titled “自定义网格:Mesh2D”Mesh2D 组件渲染任意的索引三角形列表——程序化地形切片、径向血条弧、水面。
在组件上编写几何(positions 是 x,y 对;逐顶点 UV 与颜色可选):
cmds.spawn() .insert(Transform, { position: { x: 0, y: 0, z: 0 } }) .insert(Mesh2D, { geometry: { positions: [0, 0, 100, 0, 50, 80], colors: [1,0,0,1, 0,1,0,1, 0,0,1,1], indices: [0, 1, 2], }, });网格共享标准渲染面:texture、color、layer、lit、parallax 和
material。场景里(或生成时)设置的几何自动上传;要在运行时改几何,走
Meshes2D 资源——setGeometry(entity, geometry) 重新上传(索引在引擎侧校验),
另有 getGeometry / clearGeometry。只改 geometry 字段本身不会被变更检测。
自定义几何:Geometry API
Section titled “自定义几何:Geometry API”Mesh2D 是组件路径,Geometry 则是即时路径:它上传一个索引顶点缓冲,交回
一个句柄由你自己绘制——配上材质用
Draw.drawMeshWithMaterial(geometry, material, transform?)(或配原始着色器用
Draw.drawMesh(geometry, shader, transform))。
import { Geometry, Draw, Material, registerDrawCallback } from 'esengine';
const quad = Geometry.createQuad(120, 120); // 1 单位 ≙ 1 设计像素const mat = Material.create({ shader }); // 一个 compileShader 材质
registerDrawCallback('custom-mesh', () => { Draw.drawMeshWithMaterial(quad, mat); // 单位矩阵变换});GeometryOptions
Section titled “GeometryOptions”| 字段 | 默认 | 说明 |
|---|---|---|
vertices |
— | 交错的顶点数据,一个 Float32Array(每次上传上限 64K 个 float)。 |
layout |
— | VertexAttributeDescriptor[]——按缓冲顺序、每个属性一个 { name, type }。 |
indices |
— | Uint16Array 或 Uint32Array 三角形列表(每次上传上限 16K 个索引)。 |
dynamic |
false |
为 updateVertices 的频繁更新分配。 |
DataType 命名每个属性的形状:Float、Float2、Float3、Float4、Int、
Int2、Int3、Int4。
方法与辅助函数
Section titled “方法与辅助函数”| 方法 | 作用 |
|---|---|
create(options) |
上传网格;返回 GeometryHandle(失败或数据超限时抛错)。 |
updateVertices(handle, vertices, offset?) |
重写 dynamic 几何的顶点数据(offset 单位 float)。 |
release(handle) / isValid(handle) |
释放 / 探测句柄。 |
createQuad(width?, height?) |
居中四边形(默认 1×1),布局为 a_position + a_texCoord。 |
createCircle(radius?, segments?) |
三角扇圆形(默认 1、32),同一布局。 |
createPolygon(points) |
由 {x, y} 点扇形三角化的多边形,UV 取自包围盒。 |
辅助网格都用双属性 Float2 位置 + Float2 UV 布局,可直接配只写片元的
.esshader 材质。
离屏目标:RenderTexture
Section titled “离屏目标:RenderTexture”小地图、头像、镜面——以及位图缓存的底层——
RenderTexture 分配一个离屏渲染目标。把绘制命令包在 begin/end 之间即渲染
进去;得到的 texture 是普通纹理句柄,哪里都能用(Sprite.texture、
Draw.texture、材质纹理参数):
import { RenderTexture, Draw } from 'esengine';
const rt = RenderTexture.create({ width: 256, height: 256, filter: 'linear' });
RenderTexture.begin(rt, viewProjection); // 你提供的正交 view-projectionDraw.circle({ x: 0, y: 0 }, 80, { r: 1, g: 0.5, b: 0, a: 1 });RenderTexture.end();
sprite.texture = rt.texture;RenderTextureOptions
Section titled “RenderTextureOptions”| 字段 | 默认 | 说明 |
|---|---|---|
width / height |
— | 目标像素尺寸(必填)。 |
depth |
true |
附加深度缓冲——纯 2D 合成可关掉省内存。 |
filter |
'nearest' |
结果被绘制时的采样过滤:'nearest' 或 'linear'。 |
| 方法 | 作用 |
|---|---|
create(options) |
分配目标;返回带 texture(组件用的资源表句柄)、textureId(底层设备 id)、width、height 的句柄。 |
begin(rt, viewProjection) |
把后续绘制重定向进目标(矩阵由你提供)。 |
end() |
结束离屏渲染,回到屏幕。 |
resize(rt, width, height) |
释放并重建——返回新句柄(texture 句柄会变)。 |
getDepthTexture(rt) |
以可采样纹理句柄取深度附件。 |
release(rt) |
释放目标及其纹理。 |
这是低层接口:它不会替你渲染场景——只是把你在 begin/end 之间画的东西,
在你构建的 view-projection 矩阵下重定向到目标。