前一节分析了一部分官方项目,包括如何引入Filament库、如何使用Filament库和Filament的渲染过程三个部分。
Filament分析-从Android官方项目分析1
接下来接续分析Android中使用Filament。
一、初始化
//编舞者
choreographer = Choreographer.getInstance()
//利用UiHelper初始化渲染窗口
setupSurfaceView()
//初始化Filament,包括engine/renderer/view/scene/camera
setupFilament()
//初始化view(filament的view,不是android的view)
setupView()
//初始化scene
setupScene()
初始化scene。
//加载渲染材质
loadMaterial()
//设置渲染材质
setupMaterial()
//初始化mesh
createMesh()
//生成材质类,
private fun loadMaterial() {
readUncompressedAsset("materials/lit.filamat").let {
material = Material.Builder().payload(it, it.remaining()).build(engine)
}
}
//由材质类生成材质实例
private fun setupMaterial() {
materialInstance = material.createInstance()
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
materialInstance.setParameter("roughness", 0.3f)
}
在readUncompressedAsset()方法中,将生成的材质文件lit.filamat转换为ByteBuffer,传递给native层,native层又调用了NioUtils.h里的方法,将ByteBuffer转换为byte[],而转换方式又调用了java层的NioUtils类提供的方法。
设置材质时,提供了几个参数:
materialInstance = material.createInstance()
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
materialInstance.setParameter("roughness", 0.3f)
其中baseColor和roughness是在lit.mat里设定的。
// List of parameters exposed by this material
parameters : [
// The color must be passed in linear space, not sRGB
{
type : float3,
name : baseColor
},
{
type : float,
name : roughness
},
{
type : samplerExternal,
name : videoTexture
},
{
type : mat4,
name : textureTransform
}
],
关于材质之后会单独分析。
二、Mesh
分析创建网格化的代码:
private fun createMesh() {
val floatSize = 4
val shortSize = 2
// A vertex is a position + a tangent frame:
// 3 floats for XYZ position, 4 floats for normal+tangents (quaternion)
val vertexSize = 3 * floatSize + 4 * floatSize
....
}
filament的顶点由2个部分组成,位置和正切值(法线+正切组成的四元数)。
位置:x/y/z 三个float
正切:四元数,4个float
为此,建立了一个顶点类Vertex,并增加了ByteBuffer的临时方法,存放顶点数据。
// Define a vertex and a function to put a vertex in a ByteBuffer
@Suppress("ArrayInDataClass")
data class Vertex(val x: Float, val y: Float, val z: Float, val tangents: FloatArray)
fun ByteBuffer.put(v: Vertex): ByteBuffer {
putFloat(v.x)
putFloat(v.y)
putFloat(v.z)
v.tangents.forEach { putFloat(it) }
return this
}
为什么用法线+正切组成的四元数存储顶点呢?
这是用于切线空间Tangent Space用的,可以参考一下文章:
切线空间
法线纹理
接下来有多个api调用,包括VertexBuffer、IndexBuffer,都是渲染引擎里的概念,可以参考OpenGL里的概念。
除了渲染材质RenderableManager外,还用上了光照LightManager、转换TransformManager。
TransformManager is used to add transform components to entities.
LightManager allows to create a light source in the scene, such as a sun or street lights.