You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LibGDX不使用ShapeRenderer配合SpriteBatch绘制线条的方法

问题根源
  • 你遇到的ShapeRenderer与SpriteBatch同用时位置偏移,核心原因是两个渲染器的投影矩阵、变换矩阵未对齐,并非二者不能同时使用。
  • 你之前尝试的Pixmap实时画线方案存在本质错误:Pixmap是CPU侧的离屏像素缓冲区,你创建Pixmap时的宽高仅为两点x轴差值、固定高度2,尺寸无法适配任意角度的线段;且调用drawLine时传入的是全局世界坐标,而非Pixmap自身的局部像素坐标,完全无法得到正确结果。此外逐帧创建Pixmap生成纹理的性能极差,不适合实时渲染场景。
  • 你用Pixmap绘制点位时的代码也存在坐标错误:2x2尺寸的Pixmap有效像素坐标范围为0~1,你调用fillCircle(2, 2, 2)时绘制坐标完全超出Pixmap边界;且SpriteBatch绘制纹理默认以左下角为锚点,你直接传入点位坐标绘制,会让点纹理的左下角对齐目标点,而非点中心对齐,这也是位置偏差的诱因之一。
可行解决方案

方案1:同步矩阵后混用ShapeRenderer与SpriteBatch(改造成本最低)

只要保证两个渲染器的矩阵参数完全一致,且不同时处于begin状态,就不会出现位置偏移问题,你之前的线段循环逻辑可以直接复用。
正确调用代码如下:

// 先结束SpriteBatch的当前渲染批次
batch.end();

// 核心步骤:将ShapeRenderer的矩阵与SpriteBatch完全同步,解决位置偏移
sr.setProjectionMatrix(batch.getProjectionMatrix());
sr.setTransformMatrix(batch.getTransformMatrix());

sr.begin(ShapeRenderer.ShapeType.Line);
sr.setColor(Color.WHITE);
// 原有循环画线逻辑无需修改
for(int i = 1; i < dotPositions.size(); i++) {
    sr.line(dotPositions.get(i-1), dotPositions.get(i));
}
sr.end();

// 后续需要继续用SpriteBatch绘制时,重新调用begin即可
batch.begin();

注意:ShapeRenderer和SpriteBatch属于独立的渲染批次,严禁嵌套调用begin/end,同一时间只能有一个渲染器处于激活状态。

方案2:纯SpriteBatch实现线条绘制(无需额外渲染器)

如果不想混用渲染器,可以通过拉伸1x1白色像素纹理的方式在SpriteBatch批次内直接画线,不需要切换批次,性能更优。
首先在资源初始化阶段(仅执行一次,不要逐帧创建)生成1x1白色基础纹理:

Pixmap whitePixelPix = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
whitePixelPix.setColor(Color.WHITE);
whitePixelPix.fill();
Texture whitePixelTex = new Texture(whitePixelPix);
whitePixelPix.dispose(); // 纹理生成后及时释放Pixmap,避免内存泄漏

封装两点画线工具方法:

/**
 * 在已激活的SpriteBatch上绘制线段
 * @param batch 处于begin状态的SpriteBatch实例
 * @param p1 线段起点
 * @param p2 线段终点
 * @param lineWidth 线条宽度(像素)
 */
private void drawLine(SpriteBatch batch, Vector2 p1, Vector2 p2, float lineWidth) {
    Vector2 delta = p2.cpy().sub(p1);
    float length = delta.len();
    float rotateAngle = delta.angleDeg();
    batch.draw(
            whitePixelTex,
            p1.x, p1.y - lineWidth / 2f,
            0f, lineWidth / 2f,
            length, lineWidth,
            1f, 1f,
            rotateAngle,
            0, 0, 1, 1,
            false, false
    );
}

批量绘制折线时直接循环调用即可,不需要中断SpriteBatch的渲染批次:

// 保证batch已经调用过begin
float lineWidth = 2f;
for(int i = 1; i < dotPositions.size(); i++) {
    drawLine(batch, dotPositions.get(i-1), dotPositions.get(i), lineWidth);
}

如果需要修复之前点位绘制的偏移问题,只需要在绘制点纹理时偏移半个纹理尺寸,让纹理中心对齐目标坐标即可:

// 2x2尺寸的点纹理,绘制时x、y各减1,让中心对齐点位
batch.draw(dotTexture, pos.x - 1, pos.y - 1);

方案3:自定义Mesh批量渲染(适合超大量点位场景)

如果你的点位规模达到数千甚至上万,逐段调用draw方法会产生较多批次开销,可以通过自定义Mesh组装所有线段的顶点数据,一次性提交GPU完成渲染,点位规模较小时前两种方案完全够用,无需额外实现。

内容的提问来源于stack exchange,提问作者eisa.exe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:27:38