我的世界渲染原理?
在回答这个问题前,我们先要理解一个概念——渲染线程(Render Thread)。 如上图,在我的世界中,每个实体(Entity)都拥有一套坐标,一套RGB颜色值和一个透明度值。当这些实体被渲染时,它们的坐标和颜色值将被传递到java的Canvas类中。而java的Canvas类又和我们熟悉的Java Swing组件有着千丝万缕的联系——事实上,Swing组件的原型就是来自游戏中的实体与网格的数据包。
当我们拖动鼠标或者敲击键盘时,我们的动作会转换为游戏中的帧序列。每帧都会有新的渲染线程开始工作,而每一个渲染线程都会独立地对当前帧的所有实体进行绘制。这样,从鼠标输入到帧展示给用户之间就建立了一条紧密联系的“隧道”,无论这条隧道是如何实现的,我们用户对于游戏的操控就会即时地反应到游戏世界中。
为了实现这一效果,我的世界的开发者想出了一个巧妙的办法来降低每次渲染时需要处理的复杂度。我以一个简单的例子来解释这个过程。假设我现在要在纸上画出一幅画,纸上的第一个像素需要4个数据才能完整地描述:X,Y两个坐标的原点和方向、红蓝橙三色的浓度以及不透明程度。如果我只给出其中两个坐标和一个颜色值,那么我就必须通过计算得到另一个坐标以及另一颜色的数值。
同样的道理,在渲染场景时,我的世界只给出了每个物体的一部分数据(如上面图中所示部分实体的坐标和一个颜色值),其它的信息需要自动补充。这个过程被称为优化(Optimization),而我世界使用的优化方法叫做Bsp树(Binary Space Partitioning Tree)。
Bsp树是一种二叉树,它可以将一组零散的数据快速重组为完整的图形。在每一帧,我的世界都使用Bsp树重新组合这36个参数,并使用OpenGL渲染出符合逻辑的连续画面。当然,这仅仅是一个简单的例子,实际的过程要复杂的多。比如,为了增加流畅感,动画的每一帧都不是完全一样的,而是像上面图那样每帧略作调整,这样做可以减小重绘时的复杂度。
除了上述内容,再说说其它一些技术,例如多线程,LWS(服务器端)等。 多线程是必须掌握的,无论是对JMM的了解还是对并发编程的理解。 多线程不是必须的,单线程也可以完成渲染,只不过无法做到实时响应罢了。 LWS(Server)方面,由于本人水平有限,只能讲讲大致的思路和方法。主要是维护一个列表,记录各个客户端的需求(变换、物理等等),然后统一发送给服务器,由服务器统一计算后发送回客户端。