Beg-in / vue-babylonjs

A ready-to-go 3d environment for Vue.js using Babylon.js
https://vuebabylonjs.com
MIT License
463 stars 73 forks source link

OBJ files uploader #66

Open JWDobken opened 4 years ago

JWDobken commented 4 years ago

I want to build a file uploader (obj, mtl, etc.) but access files directly in the browser using the FileReader API instead of sending it to a server and retrieve it from there again with the <Asset src='..'> component.

Regarding functionally this is probably very similar to this project: https://3dviewer.net/#

Now... this seems to be a good starting point. I have a very simple MWE that writes the content of an uploaded obj file to a data variable objtext but I have no idea how to load this into the Scene.

<template>
  <div>
  <file-reader @load="objtext = $event"></file-reader>
    <Scene v-model="productScene">
      <Property name="clearColor"
                color="#fff" />
      <Camera v-model="camera"
              :radius="2500"
              type="arcRotate" />
    </Scene>
  </div>
</template>

<script>
import FileReader from './FileReader.vue';

export default {
  name: 'Upload',
  components: {
    FileReader
  },
  data () {
    return {
      productScene: null,
      camera: null,
      objtext: ''
    }
  },
  watch: {
    objtext () {
      const scene = this.productScene
      // Add objtext to scene
      this.BABYLON.SceneLoader.Append('', 'data:' + this.objtext, scene, function () {
        scene.createDefaultCamera(true, true, true)
      })
  }
}
</script>

My filereader looks like:

<template>
  <div>
    <label class="text-reader">
      <input type="file"
             @change="loadTextFromFile">
    </label>
  </div>
</template>

<script>
export default {
  methods: {
    loadTextFromFile (ev) {
      const file = ev.target.files[0] // now it only holds one file
      const reader = new FileReader()

      reader.onload = e => this.$emit('load', e.target.result)
      reader.readAsText(file)
    }
  }
}
</script>
JWDobken commented 4 years ago

Within a week, I made little progress. There is some action on the upload feature, but the obj files are not shown.

This is the updated code so far:

<template>
  <div>
    <input id="files"
           type="file"
           multiple
           @change="reloadObjFiles">
    <Scene v-model="myScene"
           @scene="onScene">
      <HemisphericLight diffuse="#F00"></HemisphericLight>
      <Property name="clearColor"
                color="#fff" />
      <Camera v-model="camera"
              :radius="2500"
              type="arcRotate" />
    </Scene>
  </div>
</template>

<script>
export default {
  name: 'Upload',
  data () {
    return {
      myScene: null,
      myEntity: null,
      myBox: null,
      camera: null,
      objFile: null
    }
  },
  watch: {
    myScene () {
      // myScene is now available from the component
      // do something with it here or call a method to use it from here
    }
  },
  methods: {
    reloadObjFiles (event) {
      // vars
      // const scene = this.myScene
      console.log(event.target.files)
      this.filesInput.loadFiles(event)
    },
    onScene (scene) {
      // should be fired when the scene object has been initialized
      var babylon = this.BABYLON
      var engine = scene.getEngine()
      // var canvas = engine.getRenderingCanvas()
      var filesInput = new babylon.FilesInput(engine, null, scene, null, null, null, function () {
        babylon.Tools.ClearLogCache()
      }, null, null)

      filesInput.onProcessFileCallback = function (file, name, extension) {
        console.log('done: ' + (typeof file) + ' ' + name + ' ' + extension)
        return true
      }

      // global vars
      this.filesInput = filesInput
      this.myScene = scene
    }
  }
}
</script>

Or, check the glitch I prepared: https://glitch.com/~unequaled-rift-property