上篇在文章 Filament简介 中对Filament总体做了简单的介绍,了解到Filament是一个小巧但很
高效的渲染引擎。像其它程序学习初期的HelloWorld一样,本章我们开始介绍如何使用Filament
绘制一个简单的三角形。
在开始绘制三角形之前,Filament中有几个重要概念我们做一个简单的说明:
| Engine | 可以理解为Filament的程序入口点,主要用来跟踪用户创建的所有资源,管理渲染线程和硬件渲染。 |
| Renderer | 可以理解为操作系统的窗口 |
| SwapChain | 可以理解为操作系统的可以绘制的画布 |
| View | 用来保存可以绘制对象及其相关信息,一个View跟一个Scene相关联 |
| Scene | 可以理解为容器,包含光照和可绘制实体信息 |
| Camera | 相机信息包含投影矩阵信息及其曝光值参数 |
在开始绘制之前,我们首先要做的就是准备环境,在 Android 平台我们开发APP,主要使用
Android Studio 作为IDE,我们要做的就是将需要的依赖库文件添加到编译文件中:
dependencies {
implementation 'com.google.android.filament:filament-android:1.27.1'
implementation 'com.google.android.filament:filament-utils-android:1.27.1'
implementation 'com.google.android.filament:gltfio-android:1.27.1'
implementation 'com.google.android.filament:filamat-android:1.27.1'
}
上面引用的依赖有版本信息,Filament目前在不断更新,目前(2023-01-31)最新的版本为
v1.31.2。添加了依赖之后,我们就可以在 Android Studio 工程中进行开发。在 Android 平台上
使用 Filament 首先要做的事情就是调用:
Filament.init()
其作用就是初始化引擎环境,主要是加载so库,我们来看一下这里面的具体实现:
public class Filament {
static {
Platform.get();
System.loadLibrary("filament-jni");
}
private Filament() {
}
@SuppressWarnings("unused")
public static void init() {
}
}
上面代码主要做了两件事情:
1、初始化平台 Platform.get, 在 Android 平台主要是构建 AndroidPlatform 对象
2、加载库文件 filament-jni.so
以上工作准备完毕之后,就可以着手绘制工作。
绘制工作首先要做的工作就是准备画布。如果使用OpenGL绘制图形,在不同的平
台上需要不同的画布,在Windows平台上需要Window,在Android平台则需要 Surface。那么在
Android平台上如何提供这个Surface画布呢?
Android 平台 提供了两个控件可以提供Surface画布:
1、SurfaceView
2、TextureView
我们首先分析一下,这两个控件是如何构建 Android 平台 Surface 的。
1、通过 SurfaceView 构建 Surface
我们看一下 Android 平台 源码中 SurfaceView的主要相关代码:
public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
private static final String LOG_TAG = "SurfaceHolder";
@Override
public Surface getSurface() {
return mSurface;
}
};
/**
* Return the SurfaceHolder providing access and control over this
* SurfaceView's underlying surface.
*
* @return SurfaceHolder The holder of the surface.
*/
public SurfaceHolder getHolder() {
return mSurfaceHolder;
}
}
上述我们只列出了与Surface相关的主要代码,可以看到,可以先获取到 SurfaceHolder,然后
通过 SurfaceHolder 的成员方法 getSurface 获取到 Surface对象。
2、通过 TextureView 构建 Surface
同样的,我们看下 TextureView 的源码:
public class TextureView extends View {
/**
* Returns the {@link SurfaceTexture} used by this view. This method
* may return null if the view is not attached to a window or if the surface
* texture has not been initialized yet.
*
* @see #isAvailable()
*/
public @Nullable SurfaceTexture getSurfaceTexture() {
return mSurface;
}
}
通过 TextureView 的 getSurfaceTexture() 方法获取 SurfaceTexture对象,而后可以通过
SurfaceTexture 构建 Surface 对象:
public class Surface implements Parcelable {
public Surface(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
throw new IllegalArgumentException("surfaceTexture must not be null");
}
mIsSingleBuffered = surfaceTexture.isSingleBuffered();
synchronized (mLock) {
mName = surfaceTexture.toString();
setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
}
}
}
如上,在 Android 源码中, Surface 提供了以 SurfaceTexture 为参数的构造方法。
现在我们知道如何利用 Android 平台的基础控件获取到画布,但 Filament 渲染引擎提供的
画布为 SwapChain ,那么 Filament 是如何将二者联系起来的?
/**
* Creates an opaque {@link SwapChain} from the given OS native window handle.
*
* @param surface on Android, <b>must be</b> an instance of {@link android.view.Surface}
*
* @return a newly created {@link SwapChain} object
*
* @exception IllegalStateException can be thrown if the SwapChain couldn't be created
*/
@NonNull
public SwapChain createSwapChain(@NonNull Object surface) {
return createSwapChain(surface, SwapChain.CONFIG_DEFAULT);
}
Filament 的 Engine 类提供了成员方法 createSwapChain 将 Surface 和 SwapChain 联系了起
来。在 Filament 中 通过 UiHelper 将 Android 中控件与 SwapChain 联系起来。
public class UiHelper {
/**
* Interface used to know when the native surface is created, destroyed or resized.
*
* @see #setRenderCallback(RendererCallback)
*/
public interface RendererCallback {
/**
* Called when the underlying native window has changed.
*/
void onNativeWindowChanged(Surface surface);
/**
* Called when the surface is going away. After this call <code>isReadyToRender()</code>
* returns false. You MUST have stopped drawing when returning.
* This is called from detach() or if the surface disappears on its own.
*/
void onDetachedFromSurface();
/**
* Called when the underlying native window has been resized.
*/
void onResized(int width, int height);
}
}
UiHelper 中提供了一个接口 RenderCallback,需要用户实现该接口,主要用于创建SwapChain
class SurfaceCallback implements UiHelper.RendererCallback {
@Override
public void onNativeWindowChanged(Surface surface) {
mSwapChain = mEngine.createSwapChain(surface);
}
@Override
public void onDetachedFromSurface() {
mEngine.destroySwapChain(mSwapChain);
}
@Override
public void onResized(int width, int height) {
}
}
实现了该接口之后,将 SurfaceView 和 UiHelper 联系起来:
UiHelper uiHelper = new UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK);
uiHelper.setRenderCallback(new SurfaceCallback());
uiHelper.attachTo(mSurfaceView);
到这里我们梳理一下,我们通过 Android 的控件 SurfaceView 与 Filament 的 UiHelper 联系起
来,用于提供画布。也就是说,我们目前将画布准备好了。
下面我们就要学习该如何使用 Filament 进行渲染三角形。开始渲染之前,Filament 要求我们
必须创建几个我们在本章开篇提到的几个对象:
Engine engine = Engine.create();
Renderer renderer = engine.createRenderer();
Scene scene = engine.createScene();
View view = engine.createView();
Camera camera = engine.createCamera(engine.getEntityManager().create());
Filament 的渲染工作离不开上面几个对象,后面就需要对各个对象进行配置,最后调用下面
的语句进行具体的渲染:
if (renderer.beginFrame(mSwapChain, frameTimeNanos)) {
renderer.render(view);
renderer.endFrame();
}
其中mSwapChain 是我们前面利用 Surface 创建的对象, frameTimeNanos 是 Android 平台
的时间戳, 可通过 System.nanoTime() 获取当前时间戳。view 对象是我们前面创建的,当然
现在我们还没有对view进行配置,即使调用了以上代码也无发渲染出任何内容,我们在
下一章分析讲解具体如何配置这几个对象。
本文介绍了如何在Android应用中使用Filament渲染引擎绘制三角形。首先,通过Android Studio添加Filament依赖,接着讲解了初始化引擎环境、创建Surface的重要性。分析了SurfaceView和TextureView在构建Surface中的角色,以及Filament如何通过SwapChain与Surface关联。最后提到了在Filament中渲染前必须创建的关键对象,为后续的渲染配置做准备。
1480

被折叠的 条评论
为什么被折叠?



