From fe0f428c90f7482f43a31de0b3778f875947dddf Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Sun, 6 Feb 2022 13:47:06 +0800 Subject: [PATCH] update example project --- .../android/app/src/debug/AndroidManifest.xml | 2 +- .../MainActivity.kt | 3 +- .../polyvox_filament_example/MainActivity.kt | 425 +++++++++- .../app/src/profile/AndroidManifest.xml | 2 +- example/android/build.gradle | 3 +- example/android/settings.gradle | 18 +- example/assets/cube.bin | Bin 0 -> 82588 bytes example/assets/cube.gltf | 772 ++++++++++++++++++ .../assets/default_env/default_env_ibl.ktx | Bin 2095456 -> 2095464 bytes .../assets/default_env/default_env_skybox.ktx | Bin 1572932 -> 1572932 bytes example/lib/main.dart | 86 +- example/pubspec.yaml | 4 +- 12 files changed, 1282 insertions(+), 33 deletions(-) rename example/android/app/src/main/{kotlin/com/example/polyvox_filament_example => }/MainActivity.kt (68%) create mode 100644 example/assets/cube.bin create mode 100644 example/assets/cube.gltf diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index b7fca0d5..85639aad 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="app.polyvox.filament_example"> diff --git a/example/android/app/src/main/kotlin/com/example/polyvox_filament_example/MainActivity.kt b/example/android/app/src/main/MainActivity.kt similarity index 68% rename from example/android/app/src/main/kotlin/com/example/polyvox_filament_example/MainActivity.kt rename to example/android/app/src/main/MainActivity.kt index cf4cdf74..4442a61e 100644 --- a/example/android/app/src/main/kotlin/com/example/polyvox_filament_example/MainActivity.kt +++ b/example/android/app/src/main/MainActivity.kt @@ -1,6 +1,7 @@ -package app.polyvox.polyvox_filament_example +package app.polyvox.filament_example import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() { + } diff --git a/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt b/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt index cf4cdf74..59d17d7f 100644 --- a/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt @@ -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() +// // 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) +// // } +// // } +// } diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index b7fca0d5..85639aad 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="app.polyvox.filament_example"> diff --git a/example/android/build.gradle b/example/android/build.gradle index ed45c658..e6cb3895 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -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" + } } diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 44e62bcf..121d30d8 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -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 +} \ No newline at end of file diff --git a/example/assets/cube.bin b/example/assets/cube.bin new file mode 100644 index 0000000000000000000000000000000000000000..830b692b940ca08e1e3b4eff82cbff802ef2f5f5 GIT binary patch literal 82588 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 Z7|=1GV?f7%jsYD5ItFwM{5QwI{{hb8IXVCU literal 0 HcmV?d00001 diff --git a/example/assets/cube.gltf b/example/assets/cube.gltf new file mode 100644 index 00000000..d0d00f82 --- /dev/null +++ b/example/assets/cube.gltf @@ -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" + } + ] +} diff --git a/example/assets/default_env/default_env_ibl.ktx b/example/assets/default_env/default_env_ibl.ktx index 6194dc3f1da35e9dba3b45223e4b52f973eebd10..b2e6cbabdb557f20bd037c8877810f0dd4f457a6 100644 GIT binary patch delta 489 zcmZw9JxBs!9LMo{Nwdq&>(uKst)py`=upx2~?iwwM$0-~d zrLhN`8l$O(vWB3s`DkeDe@>YVANcb8{yZN+^D}6+tIZV4Fd{hIV^GP#mV*s#ECf_C zk#6A%On)MrY-H(rIE@BO2%BY$Fl=KLt`=4eQxAWI9Idm*qDT5G zib%dM)i}LNE0`xc1ujN<9aW@aM)`Ur>o>AQu3n;|uLTO211iXXESRTSkUQNVTO~oJ b{k8mo!4CXlBTtKsg|{BJo21dg;^y-Yz+8kS delta 505 zcmaFyss6#I`Uy7mJd6ws96(&0!C;_gZea>U3K$G713eQ1BU4MD31@0n%t`WNwVi;?e~P0*$paR=~;x zD=;uKH-Rd^U~(}qurN#)5M`8`?x!Wj)!e|?-oOaLOxqh6ndjL|uWMwNo0cRl(jH*P z48$xz%nHP8K+F!r9NPozIOklP{=l6}X8HyZ8NPNg0WKis24Wr{<^^KD?P3D_N)wn3 zyCd7J7w~VlULbJy#Pkg%tP<@8nSwwp1jNEXEVA7oQ?zc)bf;^qLfa3Bia9V(PkF;C zHhrD|6WewfNwIe~rf2aAi?u6!0%36=mH=W&AeI7R>Fo-iWF`boU&AlOHT~RIDUR)j noMj7)r%x;3=9`}Lhl{7(r(AZsPr2NIHB8CU+xb-Fqpkt~Kbwc@ diff --git a/example/assets/default_env/default_env_skybox.ktx b/example/assets/default_env/default_env_skybox.ktx index e8de441a6cbc91b6397ede5312584fde6f4fa469..74750d424b309586f5d62cc28f096276d63b0da7 100644 GIT binary patch delta 243 zcmX@okZ`0SpB=)_&_I2(xd$b(7;o+Vp?9LSox*IB-^|PLHVK5SX4Yk4s^DLmH>a zmgyVrak4NiZa;NU0Eh*FSO|!Pfmmewse__ALDSE8aGa54x`2pS#q@xmta9zkM8vi)6A_>H8URi?X9@rS delta 251 zcmX@okZ`0SpLwcyvu{6jljBDkAOaTp}z?HJAqWa|1CC5c6(d zb%(EL9h0+kyIeQ_cDZhWRc1_oU$>t+C;-HQKr95r!ayvt{nSBGouKKrw8gll-`UT| qF}+{`E6el;#~E3s3y6qSOi%bADl&b8iWpb>G7+)u%S6QIy#@f&DrlJi diff --git a/example/lib/main.dart b/example/lib/main.dart index f70c5c86..703ce136 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -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 { 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 { 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() + .toList() + + [ + 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 { // .values // .toList(), // ) + // ElevatedButton( + // child: const Text('init'), + // onPressed: () async { + // await _filamentController.initialize(); + // }), \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bee540ab..ddbfc00d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -41,7 +41,7 @@ flutter: - assets/BusterDrone/ - assets/BusterDrone/textures/ - assets/FlightHelmet/ - - assets/FlightHelmet/textures/ - - assets/textures/ + #- assets/FlightHelmet/textures/ + #- assets/textures/ \ No newline at end of file