【问题标题】:Issue when rendering fonts with libGDX at small (<0.5) scales使用 libGDX 以小 (<0.5) 比例渲染字体时出现问题
【发布时间】:2021-07-29 01:12:32
【问题描述】:

我为我的 libGDX 游戏创建了一个BitmapFont,并希望在玩家面前渲染它(在空间中的恒定位置,即像一个标志而不像一个 HUD)。可悲的是,渲染在小范围内表现得很奇怪,以至于文本变得不可读。这是怎么回事,有什么办法可以防止这种情况发生?

在 0.5F (ok) 时:

0.2F (???):

0.1F (???):

完整的minimal reproducible example(减去构建/项目文件):

  • 使用鼠标光标移动
  • 按 ESC 退出应用程序
  • 我在屏幕截图之间更改的行是font.data.setScale(-0.5F, 0.5F)
package xjcl.extracredits2020

import com.badlogic.gdx.*
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.*
import com.badlogic.gdx.math.Vector3

class RangeAnxietyGame : ApplicationAdapter() {
    lateinit var cam: PerspectiveCamera
    lateinit var spriteBatch: SpriteBatch
    lateinit var font: BitmapFont

    override fun create() {
        Gdx.input.apply { isCursorCatched = true }
        spriteBatch = SpriteBatch()
        font = BitmapFont()
        cam = PerspectiveCamera(67F, Gdx.graphics.width.toFloat(), Gdx.graphics.height.toFloat()).apply {
            position.set(Vector3(0f, 1.8f, 0f))
            lookAt(0f, 1.8f, 1f)
            update()
        }
    }

    override fun render() {
        Gdx.gl.glViewport(0, 0, Gdx.graphics.width, Gdx.graphics.height)
        Gdx.gl.glClearColor(0f, 0f, 0f, 1f)
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT or GL20.GL_DEPTH_BUFFER_BIT)

        if (Gdx.input.isKeyPressed(Input.Keys.F))
            Gdx.graphics.setFullscreenMode(Gdx.graphics.displayMode)
        if (Gdx.input.isKeyPressed(Input.Keys.G))
            Gdx.graphics.setWindowedMode(1280, 720)
        if (Gdx.input.isKeyPressed(Input.Keys.ESCAPE))
            Gdx.app.exit()

        val dt = Gdx.graphics.deltaTime  // seconds
        cam.apply {
            rotate(Gdx.input.deltaX * -20*dt, 0F, 1F, 0F)
            rotate(up.cpy().crs(direction), Gdx.input.deltaY * 10*dt)
            Gdx.input.setCursorPosition(Gdx.graphics.width/2, Gdx.graphics.height/2)
            update()
        }

        spriteBatch.apply {  // goal text -- bad and hacky
            begin()
            projectionMatrix = cam.combined.cpy().translate(0F, 0F, 50F)
            font.data.setScale(-0.5F, 0.5F)
            font.draw(this, "${cam.position.z.toInt()}m/50m\n${Gdx.graphics.width}x${Gdx.graphics.height} " +
                    "${(1 / dt).toInt()}fps\nat scale (-0.5F, 0.5F)", 0F, 0F)
            end()
        }
    }
}

此外,捕获光标首先工作但随后中断(如果我使用F 进入全屏,然后使用G 退出,则光标可以从各个方向逃逸。我也可以全屏逃逸到我的第二台显示器。 setCursorPosition 没有区别。)我应该为此发布一个单独的问题吗?

【问题讨论】:

    标签: java kotlin fonts libgdx


    【解决方案1】:

    你需要使用

    font.setUseIntegerPositions(false)
    

    所以它不会将每个字符的位置四舍五入为整数坐标。在 3D 空间中这样做是没有意义的,它会导致你的字母相互重叠。 (libGDX 默认这样做的原因是它会使以像素完美比例以 2D 呈现的文本看起来更清晰。)


    背景:您的字体似乎使用Nearest 作为缩小过滤器。最近的过滤意味着对于每个屏幕像素,它从纹理中选择最近的坐标并将其显示为屏幕像素的颜色。当绘制的纹理小于相对于屏幕像素大小的源图像大小并且您正在使用Nearest 过滤时,您将看到像屏幕截图所示的丑陋伪影。

    如果您在 3D 空间中绘制文本,最好使用 MipMapLinearNearestMipMapLinearLinear 作为缩小过滤器。这将允许 OpenGL 在源图像像素之间进行插值,使文本看起来清晰。 MipMapLinearLinear 有这两个选择的更好的外观,但代价是一些 GPU。我总是使用MipMapLinearLinear,并且从来没有让文本覆盖足够多的屏幕,以至于对性能的影响会很显着。

    要在位图字体文件中解决此问题,请找到以下行:

    filter: Nearest,Nearest
    

    并将其更改为

    filter: MipMapLinearLinear,Linear
    

    最后一个Linear是把放大滤镜设置为插值,这样当你靠近它时,文字看起来就不会像素化了。

    此外,在 Heiro 或 BMFont 或您用于创建字体的任何应用程序中应该有一个设置,因此您不必手动编辑字体文件的文本。

    【讨论】:

    • 感谢您的回答! useIntegerPositions 修复了一切!顺便说一句,我使用的是“默认”字体,我没有字体文件。
    • 哦,对了。过滤问题实际上只有在缩小到可能无法辨认的地方时才会成为问题。不过,您可能需要考虑切换过滤以使文本看起来不那么混叠。但是我认为修改默认字体的过滤以使用mip映射有点复杂。
    猜你喜欢
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 2016-02-27
    • 2012-11-08
    • 2014-10-30
    • 1970-01-01
    • 2020-12-27
    • 2016-05-31
    相关资源
    最近更新 更多