动态贴图与 LCD
车内屏幕的实现方式:用 Java2D 画到 BufferedImage,再上传成贴图。
整体流程
- 创建
GraphicsTexture - 用 Java 的
BufferedImage与Graphics2D画内容 - 调
upload()传给 GPU - 把贴图用到模型上
- 不用时
close()
GraphicsTexture
| 方法 | 说明 |
|---|---|
upload() | 上传当前内容 |
upload(image) | 上传指定的 BufferedImage |
close() | 立即释放 |
close(delay) | 延迟释放 |
isClosed() | 是否已释放 |
createArgbBufferedImage(src) | 转成 ARGB 格式,上传前通常需要 |
liveCount() | 当前存活的贴图数,排查泄漏用 |
贴图必须
close()。
每张都占显存,忘了释放就是泄漏。
在 dispose 里关掉,或用 liveCount() 盯着数量。一个 LCD 的骨架
function create(ctx, state, train) {
state.tex = null;
state.shown = null;
}
function render(ctx, state, train) {
if (!train.shouldRender()) return;
var text = train.nextStationName();
if (text === state.shown) return; // 没变就不重画
state.shown = text;
var img = new java.awt.image.BufferedImage(
512, 128, java.awt.image.BufferedImage.TYPE_INT_ARGB);
var g = img.createGraphics();
g.setColor(java.awt.Color.BLACK);
g.fillRect(0, 0, 512, 128);
g.setColor(java.awt.Color.WHITE);
g.setFont(Resources.readFont(Resources.id("mypack:font/lcd.ttf")).deriveFont(48));
g.drawString("下一站 " + text, 20, 80);
g.dispose();
if (state.tex === null) state.tex = new GraphicsTexture();
state.tex.upload(img);
}
function dispose(ctx, state, train) {
if (state.tex !== null) state.tex.close();
}
只在必要时重画
这是 LCD 脚本最容易出问题的地方。每帧重画一张 512×128 的图并上传, 一辆 8 编组的车就是每秒几百次 —— 帧率会掉得很明显。
正确做法是比对内容:站名没变、时间没跨秒、滚动位置没动,就直接返回。
上面例子里的 state.shown 就是干这个的。
贴图上限
客户端配置 scriptTextureLimit 限制脚本动态贴图的缓存数量,默认 512。
超过后旧贴图会被淘汰。