Minecraft渲染原理(0)
首先简单介绍一下 Minecraft 源码的获取方式. fabric 开发环境包含了反混淆 Minecraft 源码的工具, 因此最简单的方法是克隆一个 fabric mod 的仓库, 然后调用里面的工具. 考虑到我们的目的是修改 VulkanMod, 不妨直接 git clone https://github.com/xCollateral/VulkanMod.git
(或克隆 fabric-example-mod 也可).
在获得了 VulkanMod 的代码仓库后, 在仓库文件夹内执行 即可生成供 IDE 跳转的未混淆的源码包. 这一源码包的文件位置在1
./gradlew genSources
VulkanMod/.gradle/loom-cache/1.18.2/
下, 是一个包含了一大堆 .class
文件的 jar 包.
展开这个 jar 包(解压缩或者使用 jd-gui), 应当得到如下的目录树:
目录树
1 | . |
而我们感兴趣的内容主要集中在 net/minecraft/client/
目录下. 通过搜索所有 java 人都熟悉的 public static void main
, 我们知道可以从这一目录下的 net/minecraft/client/main/Main.java
开始梳理游戏客户端的运行逻辑.
net/minecraft/client/main/Main.java
192 |
if (minecraftClient.shouldRenderAsync()) { |
事实上, minecraftClient.shouldRenderAsync()
永远是 false
, 因此只有第二个分支会执行; 这导致主线程就是渲染线程.
我们可以据此跳转到
net/minecraft/client/MinecraftClient.java
706 |
public void run() { |
this.render(!bl)
就是我们要找的目标. 这一函数实在太长, 我们只简单罗列正常渲染一帧时其所做事项, 至于退出/重载资源等行为先不管:
- 执行 tick
- 更新鼠标位置(用于gui展开的情况)
1039
this.mouse.updateMouse();
- 对
RenderSystem.modelViewMatrix
进行一番操作1045
1046
1047MatrixStack matrixStack = RenderSystem.getModelViewStack();
matrixStack.push();
RenderSystem.applyModelViewMatrix(); - 绑定
MinecraftClient.framebuffer
对应的 FBO1049
this.framebuffer.beginWrite(true);
- 清除雾
1050
BackgroundRenderer.clearFog();
- 启用材质和剔除
1052
1053RenderSystem.enableTexture();
RenderSystem.enableCull(); - 调用
gameRenderer
进行真正的绘制1057
this.gameRenderer.render(this.paused ? this.pausedTickDelta : this.renderTickCounter.tickDelta, l, tick);
- 绘制
toast
[1]1059
this.toastManager.draw(new MatrixStack());
- 绑定默认帧缓冲
1068
this.framebuffer.endWrite();
- 将
MinecraftClient.framebuffer
对应的 FBO 的内容使用gameRenderer.blitScreenShader
绘制到默认帧缓冲上1072
this.framebuffer.draw(this.window.getFramebufferWidth(), this.window.getFramebufferHeight());
- 交换颜色缓冲, 使默认帧缓冲上的内容显示到屏幕上
1076
this.window.swapBuffers();
- 等待合适的时间以使帧率不超过设定的限制
1079
RenderSystem.limitDisplayFPS(j);
由上述过程可知, 一切的魔法都发生在 gameRenderer.render
中. 且听下回分解.
-
1.toast是Minecraft在获得成就/获得新配方/完成教程时弹出的框框,大致外观可见
assets/minecraft/textures/gui/toasts.png
. ↩︎