update example project

This commit is contained in:
Nick Fisher
2022-02-06 13:47:06 +08:00
parent abb43d351c
commit 60f245fa7f
12 changed files with 1282 additions and 33 deletions

View File

@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.polyvox.polyvox_filament_example">
package="app.polyvox.filament_example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->

View File

@@ -1,6 +1,7 @@
package app.polyvox.polyvox_filament_example
package app.polyvox.filament_example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@@ -1,6 +1,429 @@
package app.polyvox.polyvox_filament_example
package app.polyvox.filament_example
import io.flutter.embedding.android.FlutterActivity
// import com.google.android.filament.gltf.*
import com.google.android.filament.utils.*
import android.annotation.SuppressLint
import android.app.Activity
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.GestureDetector
import android.widget.TextView
import android.widget.Toast
import com.google.android.filament.Fence
import com.google.android.filament.IndirectLight
import com.google.android.filament.Skybox
import com.google.android.filament.View
import com.google.android.filament.utils.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream
import java.io.RandomAccessFile
import java.nio.Buffer
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
import java.util.zip.ZipInputStream
class MainActivity: FlutterActivity() {
}
//
// import io.flutter.embedding.android.FlutterActivity
// class MainActivity : FlutterActivity() {
// // companion object {
// // // // Load the library for the utility layer, which in turn loads gltfio and the Filament core.
// // // init { Utils.init() }
// // private const val TAG = "gltf-viewer"
// // }
// // private lateinit var surfaceView : SurfaceView
// // private lateinit var choreographer: Choreographer
// // private val frameScheduler = FrameCallback()
// // private lateinit var modelViewer: ModelViewer
// // private lateinit var titlebarHint: TextView
// // private val doubleTapListener = DoubleTapListener()
// // private lateinit var doubleTapDetector: GestureDetector
// // private var remoteServer: RemoteServer? = null
// // private var statusToast: Toast? = null
// // private var statusText: String? = null
// // private var latestDownload: String? = null
// // private val automation = AutomationEngine()
// // private var loadStartTime = 0L
// // private var loadStartFence: Fence? = null
// // private val viewerContent = AutomationEngine.ViewerContent()
// // @SuppressLint("ClickableViewAccessibility")
// // override fun onCreate(savedInstanceState: Bundle?) {
// // super.onCreate(savedInstanceState)
// // surfaceView = SurfaceView(this)
// // setContentView( surfaceView)
// // // window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// // // // titlebarHint = findViewById(R.id.user_hint)
// // // // surfaceView = findViewById(R.id.main_sv)
// // // choreographer = Choreographer.getInstance()
// // // doubleTapDetector = GestureDetector(applicationContext, doubleTapListener)
// // // modelViewer = ModelViewer(surfaceView)
// // // viewerContent.view = modelViewer.view
// // // viewerContent.sunlight = modelViewer.light
// // // viewerContent.lightManager = modelViewer.engine.lightManager
// // // viewerContent.scene = modelViewer.scene
// // // viewerContent.renderer = modelViewer.renderer
// // // surfaceView.setOnTouchListener { _, event ->
// // // modelViewer.onTouchEvent(event)
// // // doubleTapDetector.onTouchEvent(event)
// // // true
// // // }
// // // createDefaultRenderables()
// // // createIndirectLight()
// // // setStatusText("To load a new model, go to the above URL on your host machine.")
// // // val view = modelViewer.view
// // // /*
// // // * Note: The settings below are overriden when connecting to the remote UI.
// // // */
// // // // on mobile, better use lower quality color buffer
// // // view.renderQuality = view.renderQuality.apply {
// // // hdrColorBuffer = View.QualityLevel.MEDIUM
// // // }
// // // // dynamic resolution often helps a lot
// // // view.dynamicResolutionOptions = view.dynamicResolutionOptions.apply {
// // // enabled = true
// // // quality = View.QualityLevel.MEDIUM
// // // }
// // // // MSAA is needed with dynamic resolution MEDIUM
// // // view.multiSampleAntiAliasingOptions = view.multiSampleAntiAliasingOptions.apply {
// // // enabled = true
// // // }
// // // // FXAA is pretty cheap and helps a lot
// // // view.antiAliasing = View.AntiAliasing.FXAA;
// // // // ambient occlusion is the cheapest effect that adds a lot of quality
// // // view.ambientOcclusionOptions = view.ambientOcclusionOptions.apply {
// // // enabled = true
// // // }
// // // // bloom is pretty expensive but adds a fair amount of realism
// // // view.bloomOptions = view.bloomOptions.apply {
// // // enabled = true
// // // }
// // // remoteServer = RemoteServer(8082)
// // }
// // private fun createDefaultRenderables() {
// // val buffer = assets.open("models/scene.gltf").use { input ->
// // val bytes = ByteArray(input.available())
// // input.read(bytes)
// // ByteBuffer.wrap(bytes)
// // }
// // modelViewer.loadModelGltfAsync(buffer) { uri -> readCompressedAsset("models/$uri") }
// // updateRootTransform()
// // }
// // private fun createIndirectLight() {
// // val engine = modelViewer.engine
// // val scene = modelViewer.scene
// // val ibl = "default_env"
// // readCompressedAsset("envs/$ibl/${ibl}_ibl.ktx").let {
// // scene.indirectLight = KTXLoader.createIndirectLight(engine, it)
// // scene.indirectLight!!.intensity = 30_000.0f
// // viewerContent.indirectLight = modelViewer.scene.indirectLight
// // }
// // readCompressedAsset("envs/$ibl/${ibl}_skybox.ktx").let {
// // scene.skybox = KTXLoader.createSkybox(engine, it)
// // }
// // }
// // private fun readCompressedAsset(assetName: String): ByteBuffer {
// // val input = assets.open(assetName)
// // val bytes = ByteArray(input.available())
// // input.read(bytes)
// // return ByteBuffer.wrap(bytes)
// // }
// // private fun clearStatusText() {
// // statusToast?.let {
// // it.cancel()
// // statusText = null
// // }
// // }
// // private fun setStatusText(text: String) {
// // runOnUiThread {
// // if (statusToast == null || statusText != text) {
// // statusText = text
// // statusToast = Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT)
// // statusToast!!.show()
// // }
// // }
// // }
// // private suspend fun loadGlb(message: RemoteServer.ReceivedMessage) {
// // withContext(Dispatchers.Main) {
// // modelViewer.destroyModel()
// // modelViewer.loadModelGlb(message.buffer)
// // updateRootTransform()
// // loadStartTime = System.nanoTime()
// // loadStartFence = modelViewer.engine.createFence()
// // }
// // }
// // private suspend fun loadHdr(message: RemoteServer.ReceivedMessage) {
// // withContext(Dispatchers.Main) {
// // val engine = modelViewer.engine
// // val equirect = HDRLoader.createTexture(engine, message.buffer)
// // if (equirect == null) {
// // setStatusText("Could not decode HDR file.")
// // } else {
// // setStatusText("Successfully decoded HDR file.")
// // val context = IBLPrefilterContext(engine)
// // val equirectToCubemap = IBLPrefilterContext.EquirectangularToCubemap(context)
// // val skyboxTexture = equirectToCubemap.run(equirect)!!
// // engine.destroyTexture(equirect)
// // val specularFilter = IBLPrefilterContext.SpecularFilter(context)
// // val reflections = specularFilter.run(skyboxTexture)
// // val ibl = IndirectLight.Builder()
// // .reflections(reflections)
// // .intensity(30000.0f)
// // .build(engine)
// // val sky = Skybox.Builder().environment(skyboxTexture).build(engine)
// // specularFilter.destroy();
// // equirectToCubemap.destroy();
// // context.destroy();
// // // destroy the previous IBl
// // engine.destroyIndirectLight(modelViewer.scene.indirectLight!!);
// // engine.destroySkybox(modelViewer.scene.skybox!!);
// // modelViewer.scene.skybox = sky
// // modelViewer.scene.indirectLight = ibl
// // viewerContent.indirectLight = ibl
// // }
// // }
// // }
// // private suspend fun loadZip(message: RemoteServer.ReceivedMessage) {
// // // To alleviate memory pressure, remove the old model before deflating the zip.
// // withContext(Dispatchers.Main) {
// // modelViewer.destroyModel()
// // }
// // // Large zip files should first be written to a file to prevent OOM.
// // // It is also crucial that we null out the message "buffer" field.
// // val (zipStream, zipFile) = withContext(Dispatchers.IO) {
// // val file = File.createTempFile("incoming", "zip", cacheDir)
// // val raf = RandomAccessFile(file, "rw")
// // raf.getChannel().write(message.buffer);
// // message.buffer = null
// // raf.seek(0)
// // Pair(FileInputStream(file), file)
// // }
// // // Deflate each resource using the IO dispatcher, one by one.
// // var gltfPath: String? = null
// // var outOfMemory: String? = null
// // val pathToBufferMapping = withContext(Dispatchers.IO) {
// // val deflater = ZipInputStream(zipStream)
// // val mapping = HashMap<String, Buffer>()
// // while (true) {
// // val entry = deflater.nextEntry ?: break
// // if (entry.isDirectory) continue
// // // This isn't strictly required, but as an optimization
// // // we ignore common junk that often pollutes ZIP files.
// // if (entry.name.startsWith("__MACOSX")) continue
// // if (entry.name.startsWith(".DS_Store")) continue
// // val uri = entry.name
// // val byteArray: ByteArray? = try {
// // deflater.readBytes()
// // }
// // catch (e: OutOfMemoryError) {
// // outOfMemory = uri
// // break
// // }
// // Log.i(TAG, "Deflated ${byteArray!!.size} bytes from $uri")
// // val buffer = ByteBuffer.wrap(byteArray)
// // mapping[uri] = buffer
// // if (uri.endsWith(".gltf") || uri.endsWith(".glb")) {
// // gltfPath = uri
// // }
// // }
// // mapping
// // }
// // zipFile.delete()
// // if (gltfPath == null) {
// // setStatusText("Could not find .gltf or .glb in the zip.")
// // return
// // }
// // if (outOfMemory != null) {
// // setStatusText("Out of memory while deflating $outOfMemory")
// // return
// // }
// // val gltfBuffer = pathToBufferMapping[gltfPath]!!
// // // The gltf is often not at the root level (e.g. if a folder is zipped) so
// // // we need to extract its path in order to resolve the embedded uri strings.
// // var gltfPrefix = gltfPath!!.substringBeforeLast('/', "")
// // if (gltfPrefix.isNotEmpty()) {
// // gltfPrefix += "/"
// // }
// // withContext(Dispatchers.Main) {
// // if (gltfPath!!.endsWith(".glb")) {
// // modelViewer.loadModelGlb(gltfBuffer)
// // } else {
// // modelViewer.loadModelGltf(gltfBuffer) { uri ->
// // val path = gltfPrefix + uri
// // if (!pathToBufferMapping.contains(path)) {
// // Log.e(TAG, "Could not find $path in the zip.")
// // setStatusText("Zip is missing $path")
// // }
// // pathToBufferMapping[path]
// // }
// // }
// // updateRootTransform()
// // loadStartTime = System.nanoTime()
// // loadStartFence = modelViewer.engine.createFence()
// // }
// // }
// // override fun onResume() {
// // super.onResume()
// // choreographer.postFrameCallback(frameScheduler)
// // }
// // override fun onPause() {
// // super.onPause()
// // choreographer.removeFrameCallback(frameScheduler)
// // }
// // override fun onDestroy() {
// // super.onDestroy()
// // choreographer.removeFrameCallback(frameScheduler)
// // remoteServer?.close()
// // }
// // fun loadModelData(message: RemoteServer.ReceivedMessage) {
// // Log.i(TAG, "Downloaded model ${message.label} (${message.buffer.capacity()} bytes)")
// // clearStatusText()
// // // titlebarHint.text = message.label
// // CoroutineScope(Dispatchers.IO).launch {
// // if (message.label.endsWith(".zip")) {
// // loadZip(message)
// // } else if (message.label.endsWith(".hdr")) {
// // loadHdr(message)
// // } else {
// // loadGlb(message)
// // }
// // }
// // }
// // fun loadSettings(message: RemoteServer.ReceivedMessage) {
// // val json = StandardCharsets.UTF_8.decode(message.buffer).toString()
// // viewerContent.assetLights = modelViewer.asset?.lightEntities
// // automation.applySettings(json, viewerContent)
// // modelViewer.view.colorGrading = automation.getColorGrading(modelViewer.engine)
// // modelViewer.cameraFocalLength = automation.viewerOptions.cameraFocalLength
// // updateRootTransform()
// // }
// // private fun updateRootTransform() {
// // if (automation.viewerOptions.autoScaleEnabled) {
// // modelViewer.transformToUnitCube()
// // } else {
// // modelViewer.clearRootTransform()
// // }
// // }
// // inner class FrameCallback : Choreographer.FrameCallback {
// // private val startTime = System.nanoTime()
// // override fun doFrame(frameTimeNanos: Long) {
// // choreographer.postFrameCallback(this)
// // loadStartFence?.let {
// // if (it.wait(Fence.Mode.FLUSH, 0) == Fence.FenceStatus.CONDITION_SATISFIED) {
// // val end = System.nanoTime()
// // val total = (end - loadStartTime) / 1_000_000
// // Log.i(TAG, "The Filament backend took $total ms to load the model geometry.")
// // modelViewer.engine.destroyFence(it)
// // loadStartFence = null
// // }
// // }
// // modelViewer.animator?.apply {
// // if (animationCount > 0) {
// // val elapsedTimeSeconds = (frameTimeNanos - startTime).toDouble() / 1_000_000_000
// // applyAnimation(0, elapsedTimeSeconds.toFloat())
// // }
// // updateBoneMatrices()
// // }
// // modelViewer.render(frameTimeNanos)
// // // Check if a new download is in progress. If so, let the user know with toast.
// // val currentDownload = remoteServer?.peekIncomingLabel()
// // if (RemoteServer.isBinary(currentDownload) && currentDownload != latestDownload) {
// // latestDownload = currentDownload
// // Log.i(TAG, "Downloading $currentDownload")
// // setStatusText("Downloading $currentDownload")
// // }
// // // Check if a new message has been fully received from the client.
// // val message = remoteServer?.acquireReceivedMessage()
// // if (message != null) {
// // if (message.label == latestDownload) {
// // latestDownload = null
// // }
// // if (RemoteServer.isJson(message.label)) {
// // loadSettings(message)
// // } else {
// // loadModelData(message)
// // }
// // }
// // }
// // }
// // // Just for testing purposes, this releases the current model and reloads the default model.
// // inner class DoubleTapListener : GestureDetector.SimpleOnGestureListener() {
// // override fun onDoubleTap(e: MotionEvent?): Boolean {
// // modelViewer.destroyModel()
// // createDefaultRenderables()
// // return super.onDoubleTap(e)
// // }
// // }
// }

View File

@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.polyvox.polyvox_filament_example">
package="app.polyvox.filament_example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->

View File

@@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.6.0'
repositories {
google()
mavenCentral()
@@ -8,6 +8,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

View File

@@ -1,11 +1,15 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}

BIN
example/assets/cube.bin Normal file

Binary file not shown.

772
example/assets/cube.gltf Normal file
View File

@@ -0,0 +1,772 @@
{
"asset" : {
"generator" : "Khronos glTF Blender I/O v1.6.16",
"version" : "2.0"
},
"scene" : 0,
"scenes" : [
{
"name" : "Scene",
"nodes" : [
0,
1,
2,
3
]
}
],
"nodes" : [
{
"mesh" : 0,
"name" : "Cube"
},
{
"name" : "Light",
"rotation" : [
0.16907575726509094,
0.7558803558349609,
-0.27217137813568115,
0.570947527885437
],
"translation" : [
4.076245307922363,
5.903861999511719,
-1.0054539442062378
]
},
{
"name" : "Camera",
"rotation" : [
0.483536034822464,
0.33687159419059753,
-0.20870360732078552,
0.7804827094078064
],
"translation" : [
7.358891487121582,
4.958309173583984,
6.925790786743164
]
},
{
"mesh" : 1,
"name" : "Cone",
"translation" : [
0,
0,
-4.3612141609191895
]
}
],
"materials" : [
{
"doubleSided" : true,
"name" : "Material",
"pbrMetallicRoughness" : {
"baseColorFactor" : [
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor" : 0,
"roughnessFactor" : 0.4000000059604645
}
}
],
"meshes" : [
{
"extras" : {
"targetNames" : [
"Key 1",
"Key 2",
"Key 3",
"Key 4",
"Key 5",
"Key 6",
"Key 7",
"Key 8"
]
},
"name" : "Cube",
"primitives" : [
{
"attributes" : {
"POSITION" : 0,
"NORMAL" : 1,
"TEXCOORD_0" : 2
},
"indices" : 3,
"material" : 0,
"targets" : [
{
"POSITION" : 4,
"NORMAL" : 5
},
{
"POSITION" : 6,
"NORMAL" : 7
},
{
"POSITION" : 8,
"NORMAL" : 9
},
{
"POSITION" : 10,
"NORMAL" : 11
},
{
"POSITION" : 12,
"NORMAL" : 13
},
{
"POSITION" : 14,
"NORMAL" : 15
},
{
"POSITION" : 16,
"NORMAL" : 17
},
{
"POSITION" : 18,
"NORMAL" : 19
}
]
}
],
"weights" : [
0,
0,
0,
0,
1,
1,
1,
1
]
},
{
"extras" : {
"targetNames" : [
"Key 1",
"Key 2",
"Key 3",
"Key 4",
"Key 5",
"Key 6"
]
},
"name" : "Cone",
"primitives" : [
{
"attributes" : {
"POSITION" : 20,
"NORMAL" : 21,
"TEXCOORD_0" : 22
},
"indices" : 23,
"targets" : [
{
"POSITION" : 24,
"NORMAL" : 25
},
{
"POSITION" : 26,
"NORMAL" : 27
},
{
"POSITION" : 28,
"NORMAL" : 29
},
{
"POSITION" : 30,
"NORMAL" : 31
},
{
"POSITION" : 32,
"NORMAL" : 33
},
{
"POSITION" : 34,
"NORMAL" : 35
}
]
}
],
"weights" : [
0,
0,
0,
0,
0,
0
]
}
],
"accessors" : [
{
"bufferView" : 0,
"componentType" : 5126,
"count" : 264,
"max" : [
1,
1,
1
],
"min" : [
-1,
-1,
-1
],
"type" : "VEC3"
},
{
"bufferView" : 1,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 2,
"componentType" : 5126,
"count" : 264,
"type" : "VEC2"
},
{
"bufferView" : 3,
"componentType" : 5123,
"count" : 276,
"type" : "SCALAR"
},
{
"bufferView" : 4,
"componentType" : 5126,
"count" : 264,
"max" : [
0.14205700159072876,
0.36317670345306396,
2.1620800495147705
],
"min" : [
-2.325753688812256,
-0.12704896926879883,
-0.1493830382823944
],
"type" : "VEC3"
},
{
"bufferView" : 5,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 6,
"componentType" : 5126,
"count" : 264,
"max" : [
0.14205700159072876,
0.6298741102218628,
0.14937379956245422
],
"min" : [
-0.5040037631988525,
-0.12704896926879883,
-0.7224071025848389
],
"type" : "VEC3"
},
{
"bufferView" : 7,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 8,
"componentType" : 5126,
"count" : 264,
"max" : [
1.1911587715148926,
0.7055504322052002,
0.14937379956245422
],
"min" : [
-0.1420515477657318,
-0.12704896926879883,
-0.9040634632110596
],
"type" : "VEC3"
},
{
"bufferView" : 9,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 10,
"componentType" : 5126,
"count" : 264,
"max" : [
1.0930120944976807,
0.12705659866333008,
0.14937379956245422
],
"min" : [
-0.1420515477657318,
-1.7105424404144287,
-0.3054158687591553
],
"type" : "VEC3"
},
{
"bufferView" : 11,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 12,
"componentType" : 5126,
"count" : 264,
"max" : [
1.0931031703948975,
7.137829303741455,
1.149359941482544
],
"min" : [
-1.0931031703948975,
-0.284426212310791,
-1.149359941482544
],
"type" : "VEC3"
},
{
"bufferView" : 13,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 14,
"componentType" : 5126,
"count" : 264,
"max" : [
0.7663934230804443,
0.12705659866333008,
0.14937379956245422
],
"min" : [
-0.1420515477657318,
-1.3416147232055664,
-1.2583342790603638
],
"type" : "VEC3"
},
{
"bufferView" : 15,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 16,
"componentType" : 5126,
"count" : 264,
"max" : [
1.0939359664916992,
0.12705659866333008,
0.14937379956245422
],
"min" : [
-0.1420515477657318,
-1.257744312286377,
-1.9783165454864502
],
"type" : "VEC3"
},
{
"bufferView" : 17,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 18,
"componentType" : 5126,
"count" : 264,
"max" : [
0.9689376950263977,
0.12705659866333008,
0.14937379956245422
],
"min" : [
-0.1420515477657318,
-1.4092154502868652,
-1.7750303745269775
],
"type" : "VEC3"
},
{
"bufferView" : 19,
"componentType" : 5126,
"count" : 264,
"type" : "VEC3"
},
{
"bufferView" : 20,
"componentType" : 5126,
"count" : 128,
"max" : [
1,
1,
1
],
"min" : [
-1,
-1,
-1
],
"type" : "VEC3"
},
{
"bufferView" : 21,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
},
{
"bufferView" : 22,
"componentType" : 5126,
"count" : 128,
"type" : "VEC2"
},
{
"bufferView" : 23,
"componentType" : 5123,
"count" : 186,
"type" : "SCALAR"
},
{
"bufferView" : 24,
"componentType" : 5126,
"count" : 128,
"max" : [
0,
0.5201449394226074,
0
],
"min" : [
0,
0,
0
],
"type" : "VEC3"
},
{
"bufferView" : 25,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
},
{
"bufferView" : 26,
"componentType" : 5126,
"count" : 128,
"max" : [
5.200448989868164,
0,
0
],
"min" : [
0,
0,
0
],
"type" : "VEC3"
},
{
"bufferView" : 27,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
},
{
"bufferView" : 28,
"componentType" : 5126,
"count" : 128,
"max" : [
0,
0,
0
],
"min" : [
0,
0,
-1.9945937395095825
],
"type" : "VEC3"
},
{
"bufferView" : 29,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
},
{
"bufferView" : 30,
"componentType" : 5126,
"count" : 128,
"max" : [
0,
0,
0
],
"min" : [
0,
0,
0
],
"type" : "VEC3"
},
{
"bufferView" : 31,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
},
{
"bufferView" : 32,
"componentType" : 5126,
"count" : 128,
"max" : [
0,
0,
0
],
"min" : [
0,
0,
0
],
"type" : "VEC3"
},
{
"bufferView" : 33,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
},
{
"bufferView" : 34,
"componentType" : 5126,
"count" : 128,
"max" : [
0,
0,
0
],
"min" : [
0,
0,
0
],
"type" : "VEC3"
},
{
"bufferView" : 35,
"componentType" : 5126,
"count" : 128,
"type" : "VEC3"
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 0
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 3168
},
{
"buffer" : 0,
"byteLength" : 2112,
"byteOffset" : 6336
},
{
"buffer" : 0,
"byteLength" : 552,
"byteOffset" : 8448
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 9000
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 12168
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 15336
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 18504
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 21672
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 24840
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 28008
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 31176
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 34344
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 37512
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 40680
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 43848
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 47016
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 50184
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 53352
},
{
"buffer" : 0,
"byteLength" : 3168,
"byteOffset" : 56520
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 59688
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 61224
},
{
"buffer" : 0,
"byteLength" : 1024,
"byteOffset" : 62760
},
{
"buffer" : 0,
"byteLength" : 372,
"byteOffset" : 63784
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 64156
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 65692
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 67228
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 68764
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 70300
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 71836
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 73372
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 74908
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 76444
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 77980
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 79516
},
{
"buffer" : 0,
"byteLength" : 1536,
"byteOffset" : 81052
}
],
"buffers" : [
{
"byteLength" : 82588,
"uri" : "cube.bin"
}
]
}

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:polyvox_filament/filament_controller.dart';
import 'package:polyvox_filament/gesture_detecting_filament_view.dart';
import 'package:polyvox_filament/view/filament_view.dart';
import 'package:polyvox_filament/view/filament_widget.dart';
void main() {
@@ -36,9 +37,14 @@ class _MyAppState extends State<MyApp> {
title: const Text('Plugin example app'),
),
body: Stack(children: [
GestureDetectingFilamentView(
controller: _filamentController,
),
Center(
child: Container(
width: 400,
height: 400,
child: FilamentWidget(
controller: _filamentController,
),
)),
Positioned.fill(
child: Wrap(
alignment: WrapAlignment.end,
@@ -56,35 +62,72 @@ class _MyAppState extends State<MyApp> {
onPressed: () async {
await _filamentController.loadGltf(
'assets/cube.gltf', 'assets');
await _filamentController.createMorpher('Cube', [0]);
}),
ElevatedButton(
child: const Text('stretch'),
child: const Text('set all weights to 1'),
onPressed: () async {
await _filamentController
.applyWeights(List.filled(8, 1.0));
}),
ElevatedButton(
child: const Text('squeeze'),
child: const Text('set all weights to 0'),
onPressed: () async {
await _filamentController
.applyWeights(List.filled(8, 0));
}),
ElevatedButton(
child: const Text('load caleb'),
onPressed: () async {
await _filamentController.loadGltf(
'assets/caleb_mouth_morph_target.gltf', 'assets');
_targets = await _filamentController
.getTargetNames('CC_Base_Body');
setState(() {});
_filamentController
.createMorpher('CC_Base_Body', [1, 7, 8]);
}),
ElevatedButton(
onPressed: () => _filamentController.playAnimation(0),
child: const Text('Play'))
child: const Text('play animation')),
ElevatedButton(
onPressed: () {
_filamentController.zoom(-1.0);
},
child: const Text('zoom in')),
ElevatedButton(
onPressed: () {
_filamentController.zoom(1.0);
},
child: const Text('zoom out')),
Builder(builder:(innerCtx) => ElevatedButton(
onPressed: () async {
final names = await _filamentController
.getTargetNames("Cube");
await showDialog(
builder: (ctx) {
return Container(
color: Colors.white,
height:200, width:200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: names
.map((name) => Text(name))
.cast<Widget>()
.toList() +
<Widget>[
ElevatedButton(
onPressed: () =>
Navigator.of(ctx).pop(),
child: Text("Close"))
]));
},
context: innerCtx);
},
child: const Text('get target names'))),
ElevatedButton(
onPressed: () async {
await _filamentController.panStart(1, 1);
await _filamentController.panUpdate(1, 2);
await _filamentController.panEnd();
},
child: Text("Pan left")),
ElevatedButton(
onPressed: () async {
await _filamentController.panStart(1, 1);
await _filamentController.panUpdate(0, 0);
await _filamentController.panEnd();
},
child: Text("Pan right"))
],
),
),
@@ -137,3 +180,8 @@ class _MyAppState extends State<MyApp> {
// .values
// .toList(),
// )
// ElevatedButton(
// child: const Text('init'),
// onPressed: () async {
// await _filamentController.initialize();
// }),

View File

@@ -41,7 +41,7 @@ flutter:
- assets/BusterDrone/
- assets/BusterDrone/textures/
- assets/FlightHelmet/
- assets/FlightHelmet/textures/
- assets/textures/
#- assets/FlightHelmet/textures/
#- assets/textures/