这个问题是我在使用Filament时遇到,其他渲染引擎可作参考。
解决Filament中使用ARCore出现绿色闪屏的问题
问题现象
使用ARCore的工程中,出现绿屏闪烁。问题帧截图如下:
问题定位
问题来源
在filament的1.21.0之前的版本,Stream对象提供了stream(long externalTextureId)方法,允许传递一个纹理ID,之前是通过如下方式实现AR功能。
// Create the filament stream.
Stream stream =
new Stream.Builder()
.stream(textureId)
.width(width)
.height(height)
.build(engine);
initialize(stream);
而在1.21.0之后的版本,stream(textureId)方法已过时,官方推荐采用Texture对象的importTexture的方式去加载。故修改成如下内容
filamentTexture = new Texture.Builder()
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
.importTexture(textureId)
.build(engine.getFilamentEngine());
实测,也能运行,但是偶现绿屏。
解决方案
相关Issue的解决方式
方式1:类型替换
解决前,找了下Issues,发现以前有人解决过。
Issue的提出者是ThomasGorisse
ThomasGorisse 是sceneview仓库的贡献者,继20年sceneform存档以后,他先后维护了sceneform、sceneview。
Texture from a GLuint texture ID #5513
一句话,就是采用SAMPLER_2D 类型替换SAMPLER_EXTERNAL类型。
方式2:使用ARCore的setCameraTextureNames 替换setCameraTextureName
使用更多的纹理对象
这里引入
pixelflinger
的回答:(pixelflinger commented on May 3, 2022)
I think the problem is that you need to call setCameraTextureNames on ARCore with enough textures – probably at least 4., the problem here is that there is only a single texture that is used at the same time for texturing and camera capture.
green flickering and laggy camera stream in android #5498
实际上,ThomasGorisse 的sceneview仓库即是采用这个解决方案,他采用了6个纹理对象。
ARCameraStream
如下:
/**
* Passing multiple textures allows for a multithreaded rendering pipeline
*/
val cameraTextureIds = IntArray(6) { OpenGL.createExternalTextureId() }
我的解决方式
一句话概括
FPS控制在30即可解决问题
为什么我会想到这样去解决?
记得以前使用ARCore,画面FPS即为30。不记得在哪里看到过条评论,说ARCore在1.26版本以后采用Camera2。
由于时间有限,未作深究,以下是我的推测:
最新的ARCore,刷新率有明显提升,但是若是某帧画面未及时返回,所以会导致这一帧在Filament中渲染就是绿色的。
为什么我不采用使用更多的纹理对象去解决?
因为只有ARCore提供了setCameraTextureNames 这个方法,而AREngine只有setCameraTextureName方法。况且若是使用多个纹理对象,之前集成的其他内容都会受到这里的改动而导致未知的问题。
部分步骤
1、重新编译材质
为实现AR的功能,此前我们用了一个材质文件,用于关联相机视频流。
此时,我们需要修改材质文件,并重新编译。
将‘samplerExternal’修改为‘sampler2d’
旧材质
material {
name : flat,
shadingModel : unlit,
blending : opaque,
parameters : [
{
type : samplerExternal,
name : cameraTexture
},
{
type : float4x4,
name : uvTransform
}
],
requires : [
uv0
]
}
......
新材质
material {
name : flat,
vertexDomain : device,
shadingModel : unlit,
blending : opaque,
culling : none,
parameters : [
{
type : sampler2d,
name : cameraTexture
},
{
type : float4x4,
name : uvTransform
}
],
requires : [
uv0
]
}
...
2、使用SAMPLER_2D类型
filamentTexture = Texture.Builder()
.width(resolution.width)
.height(resolution.height)
.levels(1)
.sampler(Texture.Sampler.SAMPLER_2D)
.format(Texture.InternalFormat.RGBA8)
.importTexture(externalTextureId.toLong())
.build(filamentEngine)
更多代码可转至开源项目“Sceneform-EQR”中查看