两个点确定一条直线,三个点确定一个平面,相信大家看了 SceneForm 的 API 会发现,绘制直线的比较好处理,凭空添加平面就很少见了,这篇文章就是基于这个需求做的
代码逻辑其实很简单,使用 RenderableDefinition.builder 自定义模型形状,arFragment 是 CleanArFragment 类型的,CleanArFragment 源码在《ARCore 使用 SceneForm 框架 —— 三维空间中不基于 Plane 加载 3D 模型》已经贴出,看看代码
/**
* 绘制三角形平面
* context: 上下文,用于获取纹理资源
* allSetPoint: 顶点集合
* arFragment: 用于渲染的 ArFragment
*/
fun buildPolygon(context : Context, allSetPoint : MutableList<Vector3>, arFragment : CleanArFragment) {
var anchorsList = ArrayList<AnchorNode>()
// 设置三角形各个顶点的位置
for (j in 0 .. (allSetPoint.size - 1)) {
val anchorNode = AnchorNode()
anchorNode.worldPosition = allSetPoint.get(j)
anchorNode.setParent(arFragment!!.arSceneView.scene)
anchorsList.add(anchorNode)
}
// 绘制三角形模型,强制限制三个顶点
if (anchorsList.size == 3) {
Texture.builder()
.setSource(context, R.drawable.final_point) // 纹理资源
.build()
.thenAccept { texture ->
MaterialFactory.makeOpaqueWithTexture(context, texture)
.thenAccept { material ->
// 将生成的三角形模型添加到场景中
val node = Node()
val triangle = makeTriangleWithAnchors(anchorsList, material)
if (triangle != null) {
node.setParent(arFragment!!.arSceneView.scene)
node.renderable = triangle
}
}
}
}
}
// 构建三角形平面
private fun makeTriangleWithAnchors(anchorNodes : List<AnchorNode>, material : Material) : ModelRenderable {
var p0 = anchorNodes.get(0).getLocalPosition()
var p1 = anchorNodes.get(1).getLocalPosition()
var p2 = anchorNodes.get(2).getLocalPosition()
var up = Vector3.up()
var uvTop = Vertex.UvCoordinate(0.5f, 1.0f)
var uvBotLeft = Vertex.UvCoordinate(0.0f, 0.0f)
var uvBotRight = Vertex.UvCoordinate(1.0f, 0.0f)
var vertices = ArrayList (
Arrays.asList(
Vertex.builder().setPosition(p0).setNormal(up).setUvCoordinate(uvTop).build(),
Vertex.builder().setPosition(p1).setNormal(up).setUvCoordinate(uvBotRight).build(),
Vertex.builder().setPosition(p2).setNormal(up).setUvCoordinate(uvBotLeft).build()
))
var triangleIndices : MutableList<Int> = ArrayList(6);
triangleIndices.add(0)
triangleIndices.add(2)
triangleIndices.add(1)
triangleIndices.add(0)
triangleIndices.add(1)
triangleIndices.add(2)
// 通过 RenderableDefinition.builder 自定义模型形状
var submesh = RenderableDefinition.Submesh.builder()
.setTriangleIndices(triangleIndices)
.setMaterial(material)
.build()
var renderableDefinition = RenderableDefinition.builder()
.setVertices(vertices)
.setSubmeshes(Arrays.asList(submesh))
.build()
var future = ModelRenderable.builder()
.setSource(renderableDefinition)
.build()
var result : ModelRenderable
try {
result = future.get() as ModelRenderable
} catch ( e : Exception ) {
throw Exception("creating model error. ", e);
}
return result
}
效果图如下,为了证明是 3D 效果,取了多个角度的效果