Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Non-DOM components with WebGL in Vue.js

yomotsu
November 10, 2018

Non-DOM components with WebGL in Vue.js

Both in English and Japanese.
The example code can be seen below:
https://github.com/yomotsu/vue-webgl-non-dom-component-example

yomotsu

November 10, 2018
Tweet

More Decks by yomotsu

Other Decks in Programming

Transcript

  1. Frontend Engineer
    at PixelGrid, Inc.
    Akihiro Oyamada
    @yomotsu

    View full-size slide

  2. https://ff-wear.com/?template=2_59832150-1541043364

    View full-size slide

  3. https://twitter.com/aniplex_plus/status/779261285783392256
    http://yomotsu.net/blog/assets/2016-12-25-xmas/
    Made with +

    View full-size slide

  4. Excuse: This topic is considered as

    Experimental

    View full-size slide

  5. ͝஫ҙɿ

    ࢼͯ͠Έͨྫͷ঺հͰ͢
    ʢϕετϓϥΫςΟεͰ͸͋Γ·ͤΜʣ

    View full-size slide

  6. • High optimized rendering performances
    • Advanced effects with GLSL Filters
    beyond CSS
    • Yet Vue can handle UI, data and APIs
    Why with WebGL?

    View full-size slide

  7. w ߴ଎ͳϨϯμϦϯάύϑΥʔϚϯε
    w $44Ͱ͸Ͱ͖ͳ͍ɺ

    (-4-ʹΑΔΞυόϯευͳඳըޮՌ
    w ͨͩ͠ɺ7VFͰ6*΍σʔλͷྲྀΕ͸࡞Δ
    ͳͥ8FC(-Ͱʁ

    View full-size slide

  8. Ͳ͏΍ͬͯʁ

    View full-size slide

  9. Failure story…

    View full-size slide

  10. • WebGL is async. 

    WebGL Rendering is not synced with DOM Rendering.
    • Made a pure class,

    independent of Vue.
    Separate WebGL and Vue…

    View full-size slide

  11. w 8FC(-͸ඇಉظ

    8FC(-ͷϨϯμϦϯά͸

    %0.ϨϯμϦϯάͱ͸ผλΠϛϯά
    w 7VFʹґଘ͠ͳ͍ɺ

    ϐϡΞͳDMBTTΛ࡞ͬͨ
    8FC(-ͱ7VFΛ੾Γ཭͢

    View full-size slide

  12. Okay, I will separate them!

    View full-size slide

  13. Α͠ɺ෼͚Α͏ʂ

    View full-size slide

  14. • Same data in 2 places.

    (Vuex and the pure class)
    • Infinite loop in two-way binding.

    (Due to number precision in JS)
    • Unreadable code…
    Separate WebGL and Vue…

    View full-size slide

  15. w ಉ͡σʔλ͕̎Օॴʹ

    ʢ7VFYͱ8FC(-༻ϐϡΞΫϥεʣ
    w ૒ํ޲όΠϯυͰແݶϧʔϓ

    ʢ+4ͷ਺஋ޡࠩͷృΓ߹͍ͳͲʣ
    w ಡΈͮΒ͍ίʔυ΁ʜ
    ෼͚ͨ݁Ռʜ

    View full-size slide

  16. Solutions and Technics

    View full-size slide

  17. less Component

    View full-size slide

  18. ͕ͳ͍

    ίϯϙʔωϯτ

    View full-size slide

  19. Demo
    WebGL Canvas

    https://github.com/yomotsu/vue-webgl-non-dom-component-example
    25

    View full-size slide


  20. :width="width"
    :height="height"
    @click="rayPick"
    >

    View full-size slide

  21. mounted() {
    this.glRender = this.glRender.bind( this );
    this.renderer = new THREE.WebGLRenderer( {
    canvas: this.$el,
    stencil: false,
    alpha: true,
    } );
    ……

    View full-size slide

  22. • for
    • Init the WebGL Renderer at mounted
    • Destroy the Renderer at destroyed
    WebGL Canvas component

    View full-size slide

  23. w DBOWBTͷΈͷUFNQMBUF
    w 8FC(-3FOEFSFSΛNPVOUFEͰॳظԽ
    w %FTUSPZ࣌ʹ8FC(-3FOEFSFSΛഇغ
    8FC(-$BOWBTίϯϙʔωϯτ

    View full-size slide

  24. Demo
    DisplayObjects
    30

    View full-size slide

  25. export default {
    name: ‘DisplayObject3D’,
    ……
    render() {
    // template がないので、
    // 空の render を明示して
    // `Failed to mount component: template
    or render function not defined.`
    // のエラーを防ぐ
    }
    }

    View full-size slide

  26. created() {
    var loader = new THREE.GLTFLoader();
    loader.load(
    './vue.glb',
    ( gltf ) => {
    this.mesh = gltf.scene;
    this.mesh.userData.vuexId = this.id;
    this.mesh.traverse( ( obj ) => obj.userData.vuexId = this.id );
    this.scene.add( this.mesh );
    this.scene.add( this.transformControl );
    this.transformControl.attach( this.mesh );
    this.$emit( 'changed' );
    }
    ...

    View full-size slide

  27. • WebGL objects are not DOM.
    • is not needed.
    • But Vue props.
    Display Object components

    View full-size slide

  28. w 8FC(-಺ΦϒδΣΫτ͸%0.Ͱ͸ͳ
    ͍
    w UFNQMBUF͸ෆཁ
    w Ͱ΋1SPQT͸΄͍͠
    දࣔΦϒδΣΫτίϯϙʔωϯτ

    View full-size slide

  29. • omit
    • Void render
    • Init the component at created.
    • Dispose at destroyed.
    Display object components

    View full-size slide

  30. w UFNQMBUF͸φγ
    w SFOEFS͸Կ΋ͤ͞ͳ͍
    w DSFBUFEͰίϯϙʔωϯτΛॳظԽ
    w EFTUSPZFEͰഇغ
    දࣔΦϒδΣΫτίϯϙʔωϯτ

    View full-size slide

  31. • WebGL root component listen events.
    • Then, WebGL render.
    • Doesn't rely on Virtual-DOM.
    Render them

    View full-size slide

  32. w 8FC(-$BOWBTDPNQPOFOU͕

    ΠϕϯτΛ؂ࢹ
    w ΠϕϯτʹԠͯ͡8FC(-ͷϨϯμϦϯά
    w όʔνϟϧ%0.ʹ͸པΒͳ͍
    Ϩϯμʔ͢Δ

    View full-size slide


  33. …(snip)
    >


    {{ /* 必ず一意のkeyを入れる */ }}
    @changed="glRender"
    …(snip)
    />

    View full-size slide

  34. methods: {
    glRender() {
    if ( this.willRender ) return;
    this.willRender = true;
    requestAnimationFrame( () => {
    if ( ! this.renderer ) return;
    this.renderer.render( this.scene, this.camera );
    delete this.willRender;
    } );
    },
    …(snip)

    View full-size slide

  35. Other points

    View full-size slide

  36. ͦͷଞ

    ΍ͬͯΈͨ͜ͱ

    View full-size slide

  37. • Avoid multiple update at the sometime.
    • Combine multiple props into one object.
    • “Watch” will be also merged into one.
    Use computed for combined-props

    View full-size slide

  38. w ಉ࣌ෳ਺ճͷߋ৽Λճආ
    w QSPQTͷ૊Έ߹Θͤ͸DPNQVUFEͰҰͭʹ
    w ͜ΕʹΑΓɺ8BUDI΋Ϛʔδ͞ΕΔ
    ࠞ߹QSPQT͸DPNQVUFEͰ

    View full-size slide

  39. watch: {
    positionX() {
    ...
    },
    positionY() {
    ...
    },

    View full-size slide

  40. watch: {
    transform() {
    ...
    },

    View full-size slide

  41. computed: {
    transform() {
    return {
    positionX: this.positionX,
    positionY: this.positionY,
    positionZ: this.positionZ,
    }
    }

    View full-size slide

  42. • Texture upload (from CPU to GPU)
    • Mesh upload
    • Rendering
    WebGL is async

    View full-size slide

  43. • ςΫενϟͷΞοϓϩʔυ(CPU͔ΒGPU)
    • ϝογϡ৘ใͷΞοϓσʔτ
    • ϨϯμϦϯά
    WebGL͸ඇಉظલఏ

    View full-size slide

  44. • DOM is easier to build UI
    • Since WebGL doesn’t make DOM,

    You cannot use DOM inspector.
    • (May makes more difficult to inspect.)
    Consider using DOM

    View full-size slide

  45. w %0.ʹΑΔ6*ߏங͸؆୯
    w 8FC(-͸%0.Λ࡞Βͳ͍ͷͰ

    %0.ΠϯεϖΫλʔ͕࢖͑ͳ͍
    w ։ൃ͕େมʹͳΔ
    %0.͕࢖͑ͳ͍͔Λ࠶ݕ౼

    View full-size slide

  46. • Mount can be done without
    • Init and $mount the component
    manually.

    (But it usually for testing.)
    Manual Mounting

    View full-size slide

  47. • Mount can be done without
    • Init and $mount the component
    manually.

    (But it usually for testing.)
    खಈϚ΢ϯτ

    View full-size slide

  48. Demo
    https://github.com/yomotsu/vue-webgl-non-dom-component-example
    54

    View full-size slide

  49. // CanvasComponent(親)内で、手動でマウントする
    const displayObject3D = new DisplayObject3d( {
    propsData: {
    id: object.id,
    positionX: object.positionX,
    positionY: object.positionY,
    …(snip)
    }
    } );
    displayObject3D.$on( 'changed', () => {
    this.glRender();
    } );

    View full-size slide

  50. The new hope:

    Custom render

    comes with Vue 3

    View full-size slide

  51. WebGL is just a tool

    not the purpose.

    View full-size slide

  52. • less component

    could be a solution

    for None-DOM instances
    • Then, your data flow would be
    clearer

    View full-size slide

  53. • DOMΛ࣋ͨͳ͍Πϯελϯεͷ

    ղܾࡦͱͯ͠ͷ

    Ϩείϯϙʔωϯτ
    • σʔλͷྲྀΕ͸ΑΓ໌֬ʹ

    View full-size slide

  54. gl.finish();
    @yomotsu
    All demos can be found:

    https://github.com/yomotsu/vue-webgl-non-dom-component-example

    View full-size slide