You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android平台下将3D模型渲染至Bitmap的实现方案咨询

Android平台下将3D模型渲染至Bitmap的实现方案咨询

嘿,我来帮你梳理下Android上把3D模型渲染到Bitmap的可行方案,你之前用Filament没搞定的问题,大概率是没用到它专门的离屏渲染能力——完全不需要把TextureView挂到屏幕上就能实现渲染输出!

首选方案:用Filament的OffscreenRenderer实现离屏渲染

Filament本身就支持无UI绑定的离线渲染,核心是用OffscreenRenderer替代TextureView作为渲染目标,步骤如下:

  • 初始化核心组件:创建Filament的Engine、Scene、View、Camera,重点是用OffscreenRenderer指定渲染的分辨率,不用关联任何UI控件
  • 加载3D模型:用Filament的AssetLoader加载glTF/GLB格式的模型,把加载后的实体添加到Scene中
  • 模型变换:通过TransformManager给模型实体设置旋转、缩放参数,比如调用setTransform方法传入矩阵或者直接设置欧拉角
  • 设置光源:给Scene添加方向光、点光源等,比如创建一个Entity后初始化DirectionalLightComponent,调整光照方向、强度
  • 渲染并导出Bitmap:调用OffscreenRenderer.render(view)执行渲染,然后读取渲染缓冲区的像素数据,转换成Bitmap

给你一段简化的代码示例参考:

// 初始化Filament引擎
val engine = Engine.create()
// 创建离屏渲染器,指定输出的宽高
val renderWidth = 512
val renderHeight = 512
val offscreenRenderer = OffscreenRenderer(engine, renderWidth, renderHeight)

// 创建场景、视图和相机
val scene = engine.createScene()
val view = engine.createView().apply {
    this.scene = scene
    // 设置相机视角,比如让相机看向模型中心
    val cameraEntity = EntityManager.get().create()
    val camera = engine.createCamera(cameraEntity)
    camera.lookAt(0f, 0f, 3f, 0f, 0f, 0f, 0f, 1f, 0f)
    this.camera = camera
}

// 加载3D模型(这里以glTF为例)
val assetLoader = AssetLoader(engine, MaterialProvider(), ResourceLoader(engine))
val modelAsset = assetLoader.loadAsset("model.glb")
modelAsset.entities.forEach { scene.addEntity(it) }

// 设置模型旋转缩放
val transformManager = engine.transformManager
modelAsset.root.forEach { entity ->
    val transform = transformManager.getTransform(transformManager.getInstance(entity))
    // 比如绕Y轴旋转90度,缩放0.5倍
    transform.rotate(0f, 90f, 0f)
    transform.scale(0.5f, 0.5f, 0.5f)
    transformManager.setTransform(transformManager.getInstance(entity), transform)
}

// 添加方向光
val lightEntity = EntityManager.get().create()
engine.createDirectionalLight(lightEntity).apply {
    setColor(Color(1.0f, 0.95f, 0.8f))
    setIntensity(100000.0f)
    setDirection(0.0f, -1.0f, -1.0f)
}
scene.addEntity(lightEntity)

// 执行渲染并生成Bitmap
offscreenRenderer.render(view)
val pixelBuffer = offscreenRenderer.readPixels()
val bitmap = Bitmap.createBitmap(renderWidth, renderHeight, Bitmap.Config.ARGB_8888)
bitmap.copyPixelsFromBuffer(pixelBuffer)

// 记得清理资源
modelAsset.releaseSourceData()
offscreenRenderer.destroy()
engine.destroy()

备选方案:使用Sceneform(简化版3D框架)

如果你觉得Filament的配置有点繁琐,也可以试试Sceneform(虽然Google现在处于维护状态,但API更友好),它的SceneView支持离屏渲染,你可以创建一个不添加到布局的SceneView,完成渲染后调用sceneView.bitmap直接获取结果,模型加载、变换、光照的API也更简洁。

兜底方案:手动用OpenGL ES实现

如果上面的框架都不符合需求,你也可以直接基于OpenGL ES手动实现:自己写着色器处理光照,用Assimp等库加载3D模型,设置MVP矩阵处理变换,最后从FrameBuffer中读取像素生成Bitmap——不过这个方案需要你对OpenGL ES有一定了解,开发成本会高很多。

总结一下,你之前卡壳的点就是没用到Filament的离屏渲染能力,用OffscreenRenderer完全可以脱离UI组件完成渲染并导出Bitmap,这是目前最推荐的方案~

备注:内容来源于stack exchange,提问作者Augusto Carmo

火山引擎 最新活动