java - 使用 libGDX 以小 (<0.5) 比例渲染字体时出现问题
问题描述
我BitmapFont
为我的 libGDX 游戏创建了一个并希望在玩家面前渲染它(在空间中的恒定位置,即像一个标志而不像一个 HUD)。可悲的是,渲染在小范围内表现得很奇怪,以至于文本变得不可读。这是怎么回事,有什么办法可以防止这种情况发生吗?
完整的最小可重现示例(减去构建/项目文件):
- 使用鼠标光标移动
- 按 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
没有什么区别。)我应该为此发布一个单独的问题?
解决方案
你需要使用
font.setUseIntegerPositions(false)
所以它不会将每个字符的位置四舍五入为整数坐标。在 3D 空间中这样做是没有意义的,它会导致你的字母相互重叠。(libGDX 默认这样做的原因是它会导致以像素完美比例以 2D 呈现的文本看起来更清晰。)
背景:您的字体似乎Nearest
用作缩小过滤器。最近的过滤意味着对于每个屏幕像素,它从纹理中选择最近的坐标并将其显示为屏幕像素的颜色。当绘制的纹理小于相对于屏幕像素大小的源图像大小并且您正在使用Nearest
过滤时,您将拥有像屏幕截图所示的丑陋伪影。
如果您在 3D 空间中绘制文本,最好使用其中一个MipMapLinearNearest
或作为您的缩小过滤器。MipMapLinearLinear
这将允许 OpenGL 在源图像像素之间进行插值,使文本看起来清晰。MipMapLinearLinear
有这两个选择的更好的外观,代价是一些GPU。我总是使用MipMapLinearLinear
并且从未有过足够覆盖屏幕的文本,以至于对性能的影响会非常显着。
要在位图字体文件中解决此问题,请找到以下行:
filter: Nearest,Nearest
并将其更改为
filter: MipMapLinearLinear,Linear
最后Linear
是将放大过滤器设置为插值,这样当您靠近它时,文本看起来不会像像素化。
此外,在 Heiro 或 BMFont 或您用于创建字体的任何应用程序中应该有一个设置,因此您不必手动编辑字体文件的文本。
推荐阅读
- macos - 在 Macos 应用程序中从 swift 登录 - 它在哪里?
- c# - C# Json 对模型的响应
- javascript - 嗨,我有一个手动工作的自动幻灯片。我的问题是我希望在您按下 btns 时重置计时器(用于自动幻灯片放映)
- android - 无法解析配置“:classpath”的所有工件。找不到 protos-27.2.2.jar
- python - 如何用Qpython打开手机手电筒?
- rust - 在塔层中检索请求主体以签署 GRPC 请求
- android - Android 11 no longer able to get album by id
- kotlin - Val-property cannot override var-property
- mongodb - 聚合整个集合,查找数组之间的重复元素 - 然后打印数组/json
- json - 如何将此 JSON 字符串转换为结构?