libGDX 游戏引擎渲染3d
作为一个java开发,还是java用得顺手
按照前面的学习,试着学习用LibGDX封装好的API来渲染一个3d物体,同时分析libgdx封装的3d渲染源码
Libgdx
LibGDX游戏引擎的基本使用参考这里。
引擎中,关于3d的渲染部分,全部在com.badlogic.gdx.graphics.g3d包中,把很多OpenGL底层操作全部封装了,所以,如果我们想要直接看到libGDX渲染3d的功能效果,还是很方便的.其中有几个概念,是libGDX封装便于操作的:
代码
1 | package com.voidvvv.test; |
代码使用libgdx内置的moedel类型构建了一个方块原型,设置了vertex顶点数组,给model添加了node,然后node下面添加了一个node part作为渲染对象。
最后,使用model构建出modelinstatnce,使用model batch对modelInstance渲染。
Model
openGL中,若我们想渲染3d物体,需要一下计算公式:
我们的Model类就是为了获取Local向量而来的。
Model是一个3d物体的原型。用来表示物体本来的样子。
我们这里的Model类,存储的是上面Local的内容,可以看到,本质是个向量。我们可以看下其源码:
1 | package com.badlogic.gdx.graphics.g3d; |
里面存储的内容有 materials(材质),nodes 节点(后面会介绍),Animation 变化动画,Mesh 网格节点。
Model下面层级的关系有点类似:
nodepart 包含 mesh part
materials
材质,可以理解为我们的3d物体外表是什么样子的,常见的设置比如颜色,图片等等。
node 节点
我们的Model存储了很多的node节点,model本身没有local位置信息,只有一些物体原型数据。
而我们的Node节点,就存储了我们物体的model矩阵信息。可以看源码:
1 |
|
可以看到我们的node节点里的的确确定义了transition 位移,rotation 旋转,scale 缩放等矩阵信息。
我们的model存储了一系列的node集合,每一个node都有自己的local矩阵,这样可以更好更方便的批量渲染我们的数据。
NodePart
NodePart是Node下面更子一级的东西。我们已经知道,node节点已经存储了local矩阵信息,但是我们还需要知道我们物体原本的顶点数组,这样我们才能知道怎么渲染这个物体。
Nodepart就是node下面一系列包含顶点数组的类的集合。就好比我们的手是跟着胳膊动的,但是我们手上分别有五个手指,是各自的样子。
NodePart下面包含 material材质,MeshPart 网格部分数据,
材质比较好理解,我们node下面的每一个part都可能有不同的渲染需求,比如一个立方体,每一个面都想渲染不同颜色。
MeshPart,顾名思义,是Mesh的一部分,这个类里面存放着的是Mesh网格数据,以及当前noded part所需要这个网格的区域,用offset和size标识。
Mesh
Mesh网格,这里面存放的就是我们的顶点数组,还有索引数组。一个model可以有许多mesh,可以分给不同的node(node part)来读取渲染。
render
渲染这部分,底层就是OpenGL,使用shader,渲染顶点数组对象。但是Libgdx封装了很多实用的功能,所以我决定从源码开始看.
ModelBatch
ModelBatch 是libgdx为我们准备的渲染3d物体的一个批处理器。想要获取它的对象非常简单,我们可以直接new。
我们可以看到这个类有一些render方法,render方法有非常多的重载,我只想来详细看下这个render方法:
1 | // 因为了解这个方法就足以了解别的render方法了 |
这个方法做了以下几件事:
- 方法需要传入一个RenderableProvider
- 使用传入的RenderableProvider,配合本身内部的renderablesPool对象池,生成renderable对象放在我们当前的batch类中
- 遍历所有renderable对象,为其设置shader
其中,RenderableProvider是一个接口。接口中只有一个抽象方法:
1 | public void getRenderables (Array<Renderable> renderables, Pool<Renderable> pool); |
我们看一下它的其中一个实现类:ModelInstance的实现
1 | public void getRenderables (Array<Renderable> renderables, Pool<Renderable> pool) { |
这里可以看到就是把当前model实例中的node全部拿来遍历,然后为每个node生成renderable。再往下:
1 | protected void getRenderables (Node node, Array<Renderable> renderables, Pool<Renderable> pool) { |
对于当前node下的每一个node part,都会从我们的rederable对象池中获取一个renderable,作为其真正的到渲染物。
然后,每一个node part会把自身包含的material以及mesh part 绑定到这个renderable中,来进行渲染。
最后真正的渲染方法,在:
1 | modelBatch.end(); |
end方法就是结束一个批次,来将之前生成的所有renderable来用对应的shader进行渲染。
嗯,就先这样把