├── .babelrc
├── .eslintrc.js
├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── 87508497f55ce42b5f885b8572c2c538.jpg
├── CNAME
├── d2ff6edb998f9ad063f8.js
├── d2ff6edb998f9ad063f8.js.map
├── favicon.png
├── fb29cdf16315e8a80f65.css
├── fb29cdf16315e8a80f65.css.map
└── index.html
├── examples
├── .eslintrc.js
├── README.md
├── animation.pug
├── animation.vue
├── asset.pug
├── asset.vue
├── entity.pug
├── entity.vue
├── fragment.glsl
├── light
│ ├── directional.pug
│ ├── directional.vue
│ ├── hemispheric.pug
│ ├── hemispheric.vue
│ ├── point.pug
│ ├── point.vue
│ ├── spot.js
│ ├── spot.pug
│ └── spot.vue
├── logo.js
├── logo.pug
├── logo.vue
├── material.pug
├── material.vue
├── mesh.pug
├── mesh.vue
├── observable.js
├── observable.pug
├── observable.vue
├── physics.js
├── physics.pug
├── physics.vue
├── property.pug
├── property.vue
├── scale.pug
├── scale.vue
├── scene.pug
├── scene.vue
├── shader.js
├── shader.pug
├── shader.vue
├── side.pug
├── side.vue
├── texture.pug
├── texture.vue
└── vertex.glsl
├── package.json
├── properties.js
├── rollup.config.js
├── site
├── .eslintrc.js
├── CNAME
├── about.md
├── about.vue
├── animation.vue
├── app.vue
├── asset.vue
├── assets
│ ├── brian.jpg
│ └── github.svg
├── camera.vue
├── controls.vue
├── entity.vue
├── favicon.png
├── global.sass
├── highlight.sass
├── home.vue
├── index.js
├── index.pug
├── installation.vue
├── light.vue
├── material.vue
├── mesh.vue
├── observable.vue
├── physics.vue
├── property.vue
├── scene.vue
├── shader.vue
├── texture.vue
├── types.vue
├── variables.sass
├── vuefile.pug
└── vuefile.vue
└── src
├── animation
├── docs.md
├── index.js
└── key.js
├── api.js
├── asset
├── docs.md
└── index.js
├── camera
├── docs.md
└── index.js
├── core.js
├── docs.md
├── entity
├── abstract.js
├── docs.md
└── index.js
├── full.js
├── index.js
├── light
├── directional.js
├── docs.md
├── hemispheric.js
├── index.js
├── point.js
└── spot.js
├── material
├── docs.md
└── index.js
├── mesh
├── abstract.js
├── docs.md
└── index.js
├── mixins.js
├── observable
├── docs.md
├── index.js
├── template.pug
└── vue.pug
├── physics
├── abstract.js
├── cannon.js
├── docs.md
├── index.js
└── oimo.js
├── property
├── docs.md
└── index.js
├── scene
├── docs.md
└── index.js
├── shader
├── attribute.js
├── content.js
├── docs.md
├── fragment.js
├── index.js
├── uniform.js
├── variable.js
└── vertex.js
├── texture
├── docs.md
└── index.js
├── types
├── color.js
├── docs.md
├── matrix.js
└── vector.js
└── util
├── index.js
└── test.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "comments": false,
3 | "presets": [["@babel/preset-env", {
4 | "targets": "last 2 versions"
5 | }]],
6 | "env": {
7 | "dist": {
8 | "presets": [["@babel/preset-env", {
9 | "modules": false
10 | }]]
11 | },
12 | "test": {
13 | "presets": [["@babel/preset-env", {
14 | "modules": "commonjs"
15 | }]]
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('begin-project/lint');
4 | module.exports.rules['no-underscore-dangle'] = 0;
5 | module.exports.rules['security/detect-object-injection'] = 0;
6 | module.exports.rules['import/no-extraneous-dependencies'] = 0;
7 | module.exports.rules['global-require'] = 0;
8 | module.exports.parserOptions = { sourceType: 'module' };
9 | module.exports.rules.strict = 0;
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Minimally Reproducible Example**
14 |
25 | - link: https://glitch.com/...
26 |
27 | **To Reproduce**
28 | Steps to reproduce the behavior:
29 | 1. Go to '...'
30 | 2. Click on '....'
31 | 3. See error in (location [e.g. JavaScript Console])
32 |
33 | **Expected behavior**
34 | A clear and concise description of what you expected to happen.
35 |
36 | **Screenshots (optional)**
37 | Add any screenshots to help explain your problem, unless the minimally reproducible example is sufficient.
38 |
39 | **Environment (please complete the following information):**
40 | - Device: [e.g. Desktop or Smartphone]
41 | - OS: [e.g. Windows]
42 | - Browser [e.g. chrome, safari]
43 | - Version [e.g. 22]
44 |
45 | **Additional context**
46 | Add any other context about the problem here.
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | npm-debug.log
4 | package-lock.json
5 | dump.rdb
6 | yarn-error.log
7 | yarn.lock
8 | dist
9 | lib
10 | vendor
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # [1.0.0-beta.7](https://github.com/Beg-in/vue-babylonjs/compare/1.0.0-beta.5...1.0.0-beta.7) (2019-06-02)
2 |
3 |
4 | ### Bug Fixes
5 |
6 | * **asset:** set root mesh to single mesh if possible ([f6bc9cf](https://github.com/Beg-in/vue-babylonjs/commit/f6bc9cf))
7 | * **docs:** template highlighting issues ([16f666c](https://github.com/Beg-in/vue-babylonjs/commit/16f666c))
8 | * **observable:** fix for onentity emit ([51b7745](https://github.com/Beg-in/vue-babylonjs/commit/51b7745))
9 | * **package:** audit cleanup and peer dependencies ([266e52c](https://github.com/Beg-in/vue-babylonjs/commit/266e52c)), closes [#21](https://github.com/Beg-in/vue-babylonjs/issues/21)
10 | * **scene:** race condition with detecting a camera for exclusion of the default environment ([207df91](https://github.com/Beg-in/vue-babylonjs/commit/207df91))
11 |
12 |
13 | ### Features
14 |
15 | * **asset:** add asset component ([78116b3](https://github.com/Beg-in/vue-babylonjs/commit/78116b3))
16 | * **observable:** add support with vue custom events ([bd8dac0](https://github.com/Beg-in/vue-babylonjs/commit/bd8dac0))
17 | * **Observable:** observable events emitted by entity and scene components ([5e016cd](https://github.com/Beg-in/vue-babylonjs/commit/5e016cd)), closes [#5](https://github.com/Beg-in/vue-babylonjs/issues/5)
18 |
19 |
20 | ### BREAKING CHANGES
21 |
22 | * **package:** Babylon.js and loaders are now peer dependencies. Add `@babylonjs/core` and
23 | `@babylonjs/loaders` when using this package from npm.
24 |
25 |
26 |
27 | # [1.0.0-beta.5](https://github.com/Beg-in/vue-babylonjs/compare/1.0.0-beta.4...1.0.0-beta.5) (2018-06-13)
28 |
29 |
30 | ### Bug Fixes
31 |
32 | * **site:** fix webpack build for local development ([3e62158](https://github.com/Beg-in/vue-babylonjs/commit/3e62158))
33 |
34 |
35 |
36 | # [1.0.0-beta.4](https://github.com/Beg-in/vue-babylonjs/compare/1.0.0-beta.3...1.0.0-beta.4) (2018-05-24)
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * **esm:** support environments with esm Vue ([a2a921f](https://github.com/Beg-in/vue-babylonjs/commit/a2a921f))
42 |
43 |
44 |
45 | # [1.0.0-beta.3](https://github.com/Beg-in/vue-babylonjs/compare/1.0.0-beta.2...1.0.0-beta.3) (2018-04-21)
46 |
47 |
48 | ### Bug Fixes
49 |
50 | * **controls:** add margin bottom to controls example ([e121220](https://github.com/Beg-in/vue-babylonjs/commit/e121220))
51 |
52 |
53 |
54 | # [1.0.0-beta.2](https://github.com/Beg-in/vue-babylonjs/compare/1.0.0-beta.1...1.0.0-beta.2) (2018-03-30)
55 |
56 |
57 | ### Bug Fixes
58 |
59 | * **scene:** default environment now activates properly ([ac79e6a](https://github.com/Beg-in/vue-babylonjs/commit/ac79e6a))
60 |
61 |
62 |
63 | # [1.0.0-beta.1](https://github.com/Beg-in/vue-babylonjs/compare/0.9.0...1.0.0-beta.1) (2018-03-30)
64 |
65 |
66 |
67 | # [0.9.0](https://github.com/Beg-in/vue-babylonjs/compare/0.8.0...0.9.0) (2018-03-25)
68 |
69 |
70 | ### Features
71 |
72 | * **physics:** add physics impostor support ([cbc547a](https://github.com/Beg-in/vue-babylonjs/commit/cbc547a))
73 |
74 |
75 |
76 | # [0.8.0](https://github.com/Beg-in/vue-babylonjs/compare/0.7.1...0.8.0) (2018-03-22)
77 |
78 |
79 | ### Features
80 |
81 | * **material:** add material with pbr support ([9261b6c](https://github.com/Beg-in/vue-babylonjs/commit/9261b6c))
82 |
83 |
84 |
85 | ## [0.7.1](https://github.com/Beg-in/vue-babylonjs/compare/0.7.0...0.7.1) (2018-02-24)
86 |
87 |
88 |
89 | # [0.7.0](https://github.com/Beg-in/vue-babylonjs/compare/0.6.0...0.7.0) (2018-02-08)
90 |
91 |
92 | ### Features
93 |
94 | * **camera:** add camera component ([6829d85](https://github.com/Beg-in/vue-babylonjs/commit/6829d85))
95 | * **entity:** add propreties system ([10124f1](https://github.com/Beg-in/vue-babylonjs/commit/10124f1))
96 |
97 |
98 |
99 | # [0.6.0](https://github.com/Beg-in/vue-babylonjs/compare/0.5.0...0.6.0) (2018-02-05)
100 |
101 |
102 | ### Features
103 |
104 | * **material:** add shader uniform and attribute components ([4c17b62](https://github.com/Beg-in/vue-babylonjs/commit/4c17b62))
105 | * **material:** add shaders ([c7bd5cb](https://github.com/Beg-in/vue-babylonjs/commit/c7bd5cb))
106 | * **material:** add vertex and fragment components ([93d2959](https://github.com/Beg-in/vue-babylonjs/commit/93d2959))
107 |
108 |
109 |
110 | # [0.5.0](https://github.com/Beg-in/vue-babylonjs/compare/0.4.0...0.5.0) (2018-01-31)
111 |
112 |
113 | ### Features
114 |
115 | * **animations:** add animations ([cb8297b](https://github.com/Beg-in/vue-babylonjs/commit/cb8297b))
116 | * **animations:** add animations ([1f3482d](https://github.com/Beg-in/vue-babylonjs/commit/1f3482d))
117 |
118 |
119 |
120 | # [0.4.0](https://github.com/Beg-in/vue-babylonjs/compare/0.3.0...0.4.0) (2018-01-30)
121 |
122 |
123 | ### Features
124 |
125 | * **entity:** add entity lifecycle hooks ([4705ea4](https://github.com/Beg-in/vue-babylonjs/commit/4705ea4))
126 | * **entity:** add entity lifecycle hooks ([1072f52](https://github.com/Beg-in/vue-babylonjs/commit/1072f52))
127 |
128 |
129 |
130 | # [0.3.0](https://github.com/Beg-in/vue-babylonjs/compare/0.2.0...0.3.0) (2018-01-30)
131 |
132 |
133 | ### Features
134 |
135 | * **light:** add lights ([297622f](https://github.com/Beg-in/vue-babylonjs/commit/297622f))
136 |
137 |
138 |
139 | # [0.2.0](https://github.com/Beg-in/vue-babylonjs/compare/1c8615b...0.2.0) (2018-01-29)
140 |
141 |
142 | ### Features
143 |
144 | * **entity:** add entity and some basic meshes ([2cc7c33](https://github.com/Beg-in/vue-babylonjs/commit/2cc7c33))
145 | * **entity:** add entity and some basic meshes ([ebb4a76](https://github.com/Beg-in/vue-babylonjs/commit/ebb4a76))
146 | * **plugin:** create Vue and Vuex plugins ([1c8615b](https://github.com/Beg-in/vue-babylonjs/commit/1c8615b))
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | ### Getting Started
4 |
5 | You will need Node.js version 8.9 or higher.
6 |
7 | The development environment only supports Unix shells, i.e. Mac OS and Linux.
8 |
9 | For Windows environments, consider using Windows Subsystem for Linux or a cloud-based development server.
10 |
11 | ### Starting the Example Site
12 |
13 | ```bash
14 | $ npm install
15 | $ npm start
16 | ```
17 |
18 | Navigate your browser to http://localhost:8080
19 |
20 | Note: port may change depending on usage in your system, observe the terminal output when running the start command to see what port the site is running on.
21 | Note: this will generate library files in the `vendor` directory. These should not be modified manually and are ignored by git.
22 |
23 | ### Building the Example Site for Github Pages
24 |
25 | ```bash
26 | $ npm run build
27 | ```
28 |
29 | ### Commit Messages
30 |
31 | This repository will only support commit messages in the Angular format from Commitizen.
32 |
33 | These messages are easily produced using the interactive commitizen interface
34 |
35 | ```bash
36 | $ npm run b cz
37 | ```
38 |
39 | ### Releases
40 |
41 | Prepare the package for distribution:
42 |
43 | ```bash
44 | $ npm run dist
45 | ```
46 |
47 | This package follows Symantic Versioning use the following scripts to tag the package and update the version number.
48 |
49 | ```bash
50 | $ npm run b patch 'some-unique-release-identifier'
51 | $ npm run b minor 'some-unique-release-identifier'
52 | $ npm run b major 'some-unique-release-identifier'
53 | ```
54 |
55 | ### Programming Guidelines
56 |
57 | Examples and templates will be written in Pug instead of HTML.
58 |
59 | linting:
60 |
61 | ```bash
62 | $ npm run b lint
63 | ```
64 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Brian Jesse
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://beg-in.github.io/vue-babylonjs/)
2 | # Vue-BabylonJS
3 |
4 | Create high quality 3D graphics in the web as easily as writing HTML and CSS.
5 |
6 | Quickly make a 3D animation:
7 |
8 | 
9 |
10 | It's this easy:
11 |
12 |
13 | ```vue
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | ```
32 |
33 | It's even easier if you use [Pug (Jade)](https://pugjs.org) for templating:
34 |
35 | ```vue
36 |
37 | Scene
38 | Camera
39 | HemisphericLight(diffuse="#0000FF")
40 | Entity(:position="[0, 0, 5]")
41 | Animation(property="rotation.x" :duration="5" :end="Math.PI * 2")
42 | Animation(property="rotation.y" :duration="5" :end="Math.PI * 2")
43 | Animation(property="rotation.z" :duration="5" :end="Math.PI * 2")
44 | PointLight(diffuse="#FF0000")
45 | template(v-for="x in [0, 4, -4]")
46 | template(v-for="y in [0, 4, -4]")
47 | Box(v-for="z in [0, 4, -4]" :position="[x, y, z]" :key="`${x},${y},${z}`")
48 |
49 | ```
50 |
51 | ## Getting Started, Installation, and API Documentation
52 |
53 | [See the documentation website](https://vuebabylonjs.com)
54 |
55 | ## Updates
56 |
57 | [Subscribe to the mailing list issue to keep up with important updates](https://github.com/Beg-in/vue-babylonjs/issues/1)
58 |
59 | ## About
60 |
61 | Vue-BabylonJS is a 3D graphics component plugin for [Vue.js](https://vuejs.org/) powered by [BabylonJS](https://www.babylonjs.com/).
62 | Vue-BabylonJS draws inspiration from A-Frame, but can be more performant with the exclusion of DOM manipulation and has closer ties to JavaScript through property binding syntax in Vue. Compared to ReactVR which uses A-Frame, Vue-BabylonJS has the potential for higher performance, more organized and decoupled components, and a higher-quality rendering engine.
63 |
64 | [See the discussion on the HTML 5 Game Dev Forums](http://www.html5gamedevs.com/topic/35379-vue-integration-like-a-frame/)
65 |
66 | ### Rationale
67 |
68 | We use BabylonJS because it is the most efficient, most feature-rich, and most modern WebGL graphics library available. The addition of Vue makes the engine reactive and development becomes easier to reason about and organize. Out-of-the-box mobile support and sensible defaults make getting started a breeze.
69 |
70 | The underlying engine is easily accessible to give pros the tools to tweak every aspect of BabylonJS. The organizational structure of the library is a Component-Entity-System and the Entity component contains many powerful features such a matrix transformation to allow for interaction with the Scene graph like a group of HTML divs. Powerful tools are available such as an integrated reactive property system that enables modifying 3D objects within templates and a Shader component that makes adding WebGL shaders easy.
71 |
72 | ## Contributing
73 |
74 | See `CONTRIBUTING.md`
75 |
--------------------------------------------------------------------------------
/docs/87508497f55ce42b5f885b8572c2c538.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Beg-in/vue-babylonjs/1b8b93cea2368bc3a289fa3d30f41c2c62db673c/docs/87508497f55ce42b5f885b8572c2c538.jpg
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | vuebabylonjs.com
2 |
--------------------------------------------------------------------------------
/docs/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Beg-in/vue-babylonjs/1b8b93cea2368bc3a289fa3d30f41c2c62db673c/docs/favicon.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
Vue-BabylonJS Documentation site
--------------------------------------------------------------------------------
/examples/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('../site/.eslintrc');
2 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | ## Examples
2 |
3 | [**You probably want to see examples on the documentation website**](https://beg-in.github.io/vue-babylonjs)
4 |
5 | If you insist on browsing the examples here please note that the Vue components have been broken apart into separate files and the templates are in Pug format.
6 |
--------------------------------------------------------------------------------
/examples/animation.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera
3 | HemisphericLight(diffuse="#0000FF")
4 | Entity(:position="[0, 0, 5]")
5 | Animation(property="rotation.x" :duration="5")
6 | Key(frame="0%" :value="0")
7 | Key(frame="100%" :value="Math.PI * 2")
8 | Animation(property="rotation.y" :duration="5" :end="Math.PI * 2")
9 | Animation(property="rotation.z" :duration="5" :end="Math.PI * 2")
10 | PointLight(diffuse="#FF0000")
11 | template(v-for="x in [0, 4, -4]")
12 | template(v-for="y in [0, 4, -4]")
13 | Box(v-for="z in [0, 4, -4]" :position="[x, y, z]" :key="`${x},${y},${z}`")
14 |
--------------------------------------------------------------------------------
/examples/animation.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/asset.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate" :radius="7.5" :beta="Math.PI / 3")
3 | HemisphericLight
4 | Asset(src="https://www.babylonjs-playground.com/scenes/skull.babylon" :scaling="[0.02, 0.02, 0.02]" :position="[4, 0.5, 0]")
5 | Asset(src="https://www.babylonjs-playground.com/scenes/Buggy/glTF/buggy.gltf" :scaling="[0.02, 0.02, 0.02]" :position="[1, 0, -1]" :rotation="[0, Math.PI / 2, 0]")
6 | Asset(src="https://www.babylonjs-playground.com/scenes/StanfordBunny.obj" :scaling="[7.5, 7.5, 7.5]" :position="[-4, -0.25, -0.5]" :rotation="[0, Math.PI, 0]")
7 | Asset(src="https://rawgit.com/saswata26/misc/master/base.stl" :scaling="[0.02, 0.02, 0.02]" :position="[-2, 0, -0.5]")
8 |
--------------------------------------------------------------------------------
/examples/asset.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/entity.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate" :radius="20")
3 | DirectionalLight(v-model="myLight")
4 | HemisphericLight(emissive="#008800")
5 | PointLight(specular="#0F0")
6 |
7 | Entity (v-model="myEntity2" :position="[6, 0, 0]")
8 | Box(:position="[-3,3,3]")
9 | Box(:position="[-9,3,3]")
10 | Box(:position="[-3,-3,3]")
11 | Box(:position="[-9,-3,3]")
12 | Box(:position="[-3,3,-3]")
13 | Box(:position="[-3,-3,-3]")
14 | Box(:position="[-9,3,-3]")
15 | Box(:position="[-9,-3,-3]")
16 |
17 | Entity (v-model="myEntity21" :position="[6, 0, 0]")
18 | Animation(property="rotation.x" :duration="5")
19 | Key(frame="0%" :value="0")
20 | Key(frame="100%" :value="Math.PI * 2")
21 | Box(:position="[-4,2,2]")
22 | Material(diffuse="#00F")
23 | Box(:position="[-4,-2,2]")
24 | Material(diffuse="#00F")
25 | Box(:position="[-8,2,2]")
26 | Material(diffuse="#00F")
27 | Box(:position="[-8,-2,2]")
28 | Material(diffuse="#00F")
29 | Box(:position="[-4,2,-2]")
30 | Material(diffuse="#00F")
31 | Box(:position="[-4,-2,-2]")
32 | Material(diffuse="#00F")
33 | Box(:position="[-8,2,-2]")
34 | Material(diffuse="#00F")
35 | Box(:position="[-8,-2,-2]")
36 | Material(diffuse="#00F")
37 |
38 | Entity (v-model="myEntity1" :position="[7, 0, 0]")
39 | Animation(property="rotation.x" :duration="5")
40 | Key(frame="0%" :value="0")
41 | Key(frame="100%" :value="Math.PI * 2")
42 | PointLight(diffuse="#FF0000")
43 | Box(:position="[10,3,3]")
44 | Box(:position="[4,3,3]")
45 | Box(:position="[10,-3,3]")
46 | Box(:position="[4,-3,3]")
47 | Box(:position="[10,3,-3]")
48 | Box(:position="[4,-3,-3]")
49 | Box(:position="[4,3,-3]")
50 | Box(:position="[10,-3,-3]")
51 | Entity (v-model="myEntity11" :position="[7, 0, 0]")
52 | Box(:position="[9,2,2]")
53 | Material(diffuse="#00F")
54 | Box(:position="[9,-2,2]")
55 | Material(diffuse="#00F")
56 | Box(:position="[5,2,2]")
57 | Material(diffuse="#00F")
58 | Box(:position="[5,-2,2]")
59 | Material(diffuse="#00F")
60 | Box(:position="[9,2,-2]")
61 | Material(diffuse="#00F")
62 | Box(:position="[9,-2,-2]")
63 | Material(diffuse="#00F")
64 | Box(:position="[5,2,-2]")
65 | Material(diffuse="#00F")
66 | Box(:position="[5,-2,-2]")
67 | Material(diffuse="#00F")
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/examples/entity.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/fragment.glsl:
--------------------------------------------------------------------------------
1 | precision highp float;
2 | uniform float time;
3 | uniform vec3 color;
4 | varying float t;
5 |
6 | void main() {
7 | gl_FragColor = vec4(t * color, 1.0);
8 | }
9 |
--------------------------------------------------------------------------------
/examples/light/directional.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate")
3 | Entity
4 | Animation(property="rotation.y", :duration="5", :end="Math.PI*2")
5 | DirectionalLight(specular="#0F0", diffuse="F00", :direction="[0,0,100]")
6 | Box(:position="[-2,0,0]")
7 | Material(diffuse="#ffffff")
8 | IcoSphere(:position="[1.3,0,0]")
9 | Material(diffuse="#FF0")
10 | Animation(property="rotation.x", :duration="3", :end="Math.PI * 2")
11 | Animation(property="rotation.y", :duration="3", :end="Math.PI * 2")
12 |
--------------------------------------------------------------------------------
/examples/light/directional.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/light/hemispheric.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate")
3 | HemisphericLight(diffuse="#F00")
4 | Box(:position="[-2,0,0]")
5 | Material(diffuse="#ffffff")
6 | Animation(property="rotation.x", :duration="3", :end="Math.PI * 2")
7 | Animation(property="rotation.y", :duration="3", :end="Math.PI * -2")
8 | IcoSphere(:position="[1.3,0,0]")
9 | Material(diffuse="#FF0")
10 | Animation(property="rotation.x", :duration="3", :end="Math.PI * 2")
11 | Animation(property="rotation.y", :duration="3", :end="Math.PI * 2")
--------------------------------------------------------------------------------
/examples/light/hemispheric.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/light/point.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate")
3 | PointLight(:position="[0,0.5,0]", specular="#FF0000")
4 | IcoSphere(:position="[-3.3,1,0]")
5 | Material(diffuse="#FFFF33")
6 | IcoSphere(:position="[3.3,1,0]")
7 | Material(diffuse="#7FFF00")
8 |
--------------------------------------------------------------------------------
/examples/light/point.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/light/spot.js:
--------------------------------------------------------------------------------
1 | export default {
2 | methods: {
3 | onCamera(entity){
4 | console.log('onCamera', entity)
5 | }
6 | ,
7 | complete(state){
8 | console.log('complete',state)
9 | }
10 |
11 |
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/examples/light/spot.pug:
--------------------------------------------------------------------------------
1 | Scene(@complete="complete")
2 | Camera(type="arcRotate", @entity="onCamera")
3 | //- SpotLight(:direction="[0,0,-5]", :angle="Math.PI/2", :exponent="40",diffuse="#7FFF00",specular="#7FFF00")
4 | Spotlight(:position="[0,5,0]", specular="#FF0000")
5 | Ground(:position="[0,1,0]",:options="{width:10, height:10}")
6 | Plane(:options="{width:20, height:20}")
7 | Material(specular="#FF0")
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/light/spot.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/examples/logo.js:
--------------------------------------------------------------------------------
1 | import Side from './side.vue';
2 |
3 | export default {
4 | components: {
5 | Side,
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/examples/logo.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Property(name="clearColor" color="#FFF")
3 | Camera(type="arcRotate")
4 | HemisphericLight
5 | property(name="intensity" :float="2")
6 | Entity(:scaling="[5, 5, 5]")
7 | Animation(property="rotation.y" :duration="5" :end="-Math.PI * 2")
8 | Side
9 | Entity(:scaling="[-1, 1, 1]")
10 | Side
11 |
--------------------------------------------------------------------------------
/examples/logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/material.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate")
3 | PointLight(:position="[0, 2, -1]")
4 | Sphere(:position="[-2, 0, 0]")
5 | Material(diffuse="#00F")
6 | Cylinder(:position="[0, 0.5, 0]")
7 | Material(emissive="#008800")
8 | Box(:position="[2, 0, 0]")
9 | Material(diffuse="#F00" :metallic="0" :roughness="1")
10 |
--------------------------------------------------------------------------------
/examples/material.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/mesh.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate" :radius="15" :beta="Math.PI / 4")
3 | HemisphericLight
4 | Sphere(:position="[6,0,0]" :scaling="[1,1,1]")
5 | Torus(:position="[4, 0, 0]")
6 | Box(:v-model="myBox" :position="[2.5, 0, 0]")
7 | Material(diffuse="#F00" :metallic="0" :roughness="1")
8 | Cylinder(:position="[1, 0, 0]")
9 | Material(diffuse="#0F0" :metallic="0" :roughness="1")
10 | //DashedLines
11 | Disc(:rotation="[0, Math.PI, 0]")
12 | //Ground(:options="{width: 10, height: 10}")
13 | IcoSphere(:position="[-1, 0, 0]")
14 | //Lathe
15 | //LineSystem
16 | //Plane
17 | //PolygonMesh
18 | //Polyhedron
19 | //Ribbon(:position="[9, 0, 0]")
20 | //TiledGround
21 | TorusKnot(:position="[-6, 0, 0]")
22 | //Tube(:position="[0, 0, 10]")
23 | //ExtrudePolygon(:position="[5, 0, 0]")
24 |
--------------------------------------------------------------------------------
/examples/mesh.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/observable.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | box: null,
5 | sphere: null,
6 | time: performance.now(),
7 | frames: 0,
8 | };
9 | },
10 |
11 | computed: {
12 | scale() {
13 | let a = 2 + Math.cos(this.time * 0.001);
14 | let b = 2 + Math.sin(this.time * 0.001);
15 | return {
16 | box: [a, b, 1],
17 | sphere: [b, a, 1],
18 | };
19 | },
20 | },
21 |
22 | methods: {
23 | beforeRender() {
24 | this.time = performance.now();
25 | },
26 |
27 | onSphere(event) {
28 | console.log('onSphere', event);
29 | // the entity event includes entity reference
30 | this.sphere = event.entity;
31 | },
32 |
33 | complete(event) {
34 | console.log('complete', event);
35 | console.log('box', this.box);
36 | console.log('sphere', this.sphere);
37 | },
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/examples/observable.pug:
--------------------------------------------------------------------------------
1 | div
2 | // events take either a method name or logic content
3 | // the complete event happens after all children have been initialized and bound
4 | Scene(@complete="complete" @before-render$="beforeRender" @after-render$="++frames")
5 | // you can use v-model bindings instead of event entity reference
6 | Box(:position="[-2, 0, 5]" :scaling="scale.box" v-model="box")
7 | Sphere(:position="[2, 0, 5]" :scaling="scale.sphere" @entity="onSphere")
8 | div(v-text="`Frames: ${frames}`" style="position: absolute; color: white; bottom: 0; padding: 15px")
9 |
--------------------------------------------------------------------------------
/examples/observable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/physics.js:
--------------------------------------------------------------------------------
1 | import LogoSide from './side.vue';
2 |
3 | export default {
4 | components: {
5 | LogoSide,
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/examples/physics.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate" :radius="10" :beta="Math.PI / 4")
3 | HemisphericLight
4 | property(name="intensity" :float="2")
5 | Ground(:options="{ width: 10, height: 10 }")
6 | Physics
7 | Entity(v-for="(_, i) in Array(81).fill()"
8 | :key="i"
9 | :position="[(i % 3) - 1, 2 + Math.floor(i / 9), (Math.floor(i / 3) % 3) - 1]"
10 | :scaling="[1, 1, 0.3]")
11 | Physics(:mass="1")
12 | Entity(:scaling="[1, 1, 1 / 0.3]")
13 | LogoSide
14 | Entity(:scaling="[-1, 1, 1]")
15 | LogoSide
16 |
--------------------------------------------------------------------------------
/examples/physics.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/property.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate")
3 |
4 | // Standard Mesh component props
5 | Box(:scaling="[0.5, 1, 1]" :position="[2, 0, 0]")
6 |
7 | // Properties prop object on Entity component
8 | // $vector() helper function
9 | Sphere(:properties="{ position: $vector([-2, 0, 0]) }")
10 |
11 | // Property component
12 | Cylinder
13 | property(name="scaling" :vector="{ x: 2, y: 0.5, z: 1 }")
14 |
15 | Entity
16 | Animation(property="rotation.x" :duration="5" :end="Math.PI * 2")
17 |
18 | // Standard Light component props
19 | PointLight(diffuse="#F0F" :position="[0, 0, 4]")
20 |
21 | Entity
22 | Animation(property="rotation.y" :duration="5" :end="Math.PI * 2")
23 |
24 | // Property components
25 | PointLight
26 | property(name="diffuse" color="#0FF")
27 | property(name="position" :vector="[0, 0, 4]")
28 |
29 | Entity
30 | Animation(property="rotation.z" :duration="5" :end="Math.PI * 2")
31 |
32 | // Properties prop object on Entity component (set multiple values!)
33 | // $color() helper function
34 | PointLight(:properties="{ diffuse: $color('#FF0'), specular: $color({ r: 1, g: 0, b: 0 }) }")
35 | // Mix-and-match!
36 | property(name="position" :vector="[0, 4, 0]")
37 |
38 | // Also available:
39 | // float="..." Property component prop
40 | // matrix="..." Property component prop
41 | // any="..." Property component prop
42 | // $matrix() helper function
43 |
--------------------------------------------------------------------------------
/examples/property.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/scale.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate" :beta="Math.PI / 4" :radius="20")
3 | HemisphericLight
4 | Sphere(:position="[-8,0,3]" :scaling="[2,1,5]")
5 | Sphere(:position="[-5,0,3]" :scaling="[2,2,3]")
6 | Sphere(:position="[-1,0,3]" :scaling="[4,5,1]")
7 | Sphere(:position="[6,0,3]" :scaling="[8,5,3]")
8 | Box(:position="[0,0,-3]" :scaling="[1,2,3]")
9 | Box(:position="[-3,0,-3]" :scaling="[2,1,2]")
10 | Box(:position="[-6,0,-3]" :scaling="[1,3,4]")
11 |
--------------------------------------------------------------------------------
/examples/scale.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/scene.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Box(:position="[0, 0, 5]")
3 |
--------------------------------------------------------------------------------
/examples/scene.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/shader.js:
--------------------------------------------------------------------------------
1 | import { BABYLON } from 'vue-babylonjs';
2 |
3 | import VERTEX from './vertex.glsl';
4 | import FRAGMENT from './fragment.glsl';
5 |
6 | const NAME = 'demo';
7 |
8 | BABYLON.Effect.ShadersStore[`${NAME}VertexShader`] = VERTEX;
9 | BABYLON.Effect.ShadersStore[`${NAME}FragmentShader`] = FRAGMENT;
10 |
11 | export default {
12 | computed: {
13 | vertexShader() {
14 | return VERTEX;
15 | },
16 |
17 | fragmentShader() {
18 | return FRAGMENT;
19 | },
20 |
21 | shader() {
22 | return NAME;
23 | },
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/examples/shader.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate")
3 | Box(:position="[2, 0, 0]")
4 | Animation(property="rotation.x" :duration="5" :end="Math.PI * 2")
5 | // Use a vertex and fragment registered with ShadersStore under the same name
6 | // Safe caching, non-reactive
7 | // Recommended for reusable shader files
8 | Shader(:shader="shader")
9 | // How to set uniform values
10 | Uniform(variable="color" color="#F00")
11 | Uniform(variable="start" :float="0.5")
12 |
13 | Box(:position="[0, -2, 0]")
14 | Animation(property="rotation.y" :duration="5" :end="Math.PI * 2")
15 | // Use shaders registered with ShadersStore under specific names
16 | // Safe caching, non-reactive
17 | // Recommended for independently reusable shader files
18 | Shader(:vertex="shader" :fragment="shader")
19 | Uniform(variable="color" color="#0F0")
20 | Uniform(variable="start" :float="1")
21 |
22 | Box(:position="[-2, 0, 0]")
23 | Animation(property="rotation.x" :duration="5" :end="-Math.PI * 2")
24 | // Use the raw text content from strings defined in this component
25 | // Unsafe caching, reactive
26 | // USE A UNIQUE VALUE IN THE "name" PROPERTY FOR SAFE CACHING
27 | // Recommended for reusable shader components
28 | Shader(name="inline" :vertexShader="vertexShader" :fragmentShader="fragmentShader")
29 | Uniform(variable="color" color="#00F")
30 | Uniform(variable="start" :float="-1")
31 |
32 | Box(:position="[0, 2, 0]")
33 | Animation(property="rotation.y" :duration="5" :end="-Math.PI * 2")
34 | // Use the raw text content from strings defined in this component
35 | // Unsafe caching, reactive
36 | // USE A UNIQUE VALUE IN THE "name" PROPERTY FOR SAFE CACHING
37 | // Recommended for independently reusable shader components
38 | Shader
39 | Vertex(name="namedvertex" :content="vertexShader")
40 | Fragment(name="namedfragment" :content="fragmentShader")
41 | Uniform(variable="color" color="#FF0")
42 | Uniform(variable="start" :float="-0.5")
43 |
44 | Box
45 | Animation(property="rotation.x" :duration="5" :end="Math.PI * 2")
46 | Animation(property="rotation.y" :duration="5" :end="Math.PI * 2")
47 | Animation(property="rotation.z" :duration="5" :end="Math.PI * 2")
48 | // Use the text content inside Vertex and Fragment components
49 | // Unsafe caching, non-reactive
50 | // USE A UNIQUE VALUE IN THE "name" PROPERTY FOR SAFE CACHING
51 | // only recommended for prototyping
52 | Shader(name="text")
53 |
54 | Vertex.
55 | precision highp float;
56 | attribute vec3 position;
57 | uniform mat4 worldViewProjection;
58 | uniform float time;
59 | varying vec3 direction;
60 |
61 | void main() {
62 | gl_Position = worldViewProjection * vec4(position, 1.0);
63 | direction = position;
64 | }
65 |
66 | Fragment.
67 | precision highp float;
68 | uniform float time;
69 | varying vec3 direction;
70 |
71 | void main() {
72 | gl_FragColor = vec4(cos(time / 1000.0) * direction, 1.0);
73 | }
74 |
75 | // Others:
76 |
77 | // Box
78 | // Use an element in DOM with a pre-defined id (not recommended for Vue)
79 | Shader(name="elements" vertexElement="someid" fragmentElement="someotherid")
80 |
81 | // Box
82 | // Use an fx file on your server
83 | Shader(name="fxfile" src="/path/to/file.fx")
84 |
--------------------------------------------------------------------------------
/examples/shader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/side.pug:
--------------------------------------------------------------------------------
1 | Entity(:rotation="[-Math.PI / 2, 0, 0]" :position="[0, 0, -0.15]")
2 | ExtrudePolygon(:options="{ shape: [$vector([0.133, 0, 0.5]), $vector([0.346, 0, 0.5]), $vector([0, 0, -0.1]), $vector([0, 0, 0.269])], depth: 0.3, sideOrientation: BABYLON.Mesh.DOUBLESIDE }")
3 | Material(diffuse="#34495E" specular="#34495E" )
4 | ExtrudePolygon(:options="{ shape: [$vector([0.346, 0, 0.5]), $vector([0.577, 0, 0.5]), $vector([0, 0, -0.5]), $vector([0, 0, -0.1])], depth: 0.3, sideOrientation: BABYLON.Mesh.DOUBLESIDE }")
5 | Material(diffuse="#41B883" specular="#41B883" )
6 |
--------------------------------------------------------------------------------
/examples/side.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/texture.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Camera(type="arcRotate" :radius="3")
3 | HemisphericLight(diffuse="#F00" specular="#0F0" :direction="[-1, 1, 0]")
4 | Property(name="groundColor" color="#0F0")
5 | Sphere(:position="[-1.5, 0, 0]")
6 | Material
7 | Texture(src="https://www.babylonjs-playground.com/textures/grass.png")
8 | Sphere
9 | Material
10 | Texture(type="emissive" src="https://www.babylonjs-playground.com/textures/grass.png")
11 | Sphere(:position="[1.5, 0, 0]")
12 | Material(diffuse="#F00")
13 | Texture(type="ambient" src="https://www.babylonjs-playground.com/textures/grass.png")
14 |
--------------------------------------------------------------------------------
/examples/texture.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/vertex.glsl:
--------------------------------------------------------------------------------
1 | precision highp float;
2 | attribute vec3 position;
3 | uniform mat4 worldViewProjection;
4 | uniform float time;
5 | uniform vec3 color;
6 | uniform float start;
7 | varying float t;
8 |
9 | void main() {
10 | gl_Position = worldViewProjection * vec4(position, 1.0);
11 | t = sin((time / 1000.0) + start);
12 | }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-babylonjs",
3 | "version": "1.0.0-beta.7",
4 | "files": [
5 | "dist/*",
6 | "lib/*"
7 | ],
8 | "main": "dist/umd.js",
9 | "module": "dist/esm.js",
10 | "unpkg": "dist/umd.min.js",
11 | "jsdelivr": "dist/umd.min.js",
12 | "engines": {
13 | "node": ">=8.9"
14 | },
15 | "description": "A ready-to-go 3d environment for Vue.js using Babylon.js",
16 | "homepage": "https://github.com/Beg-in/vue-babylonjs",
17 | "repository": "Beg-in/vue-babylonjs",
18 | "bugs": {
19 | "url": "https://github.com/Beg-in/vue-babylonjs/issues"
20 | },
21 | "author": {
22 | "name": "Beg.in",
23 | "email": "info@beg.in",
24 | "url": "http://beg.in"
25 | },
26 | "contributors": [
27 | "Brian Jesse (brianjesse.com)",
28 | "Johnmark Beaty (johnmarkbeaty.com)"
29 | ],
30 | "license": "MIT",
31 | "scripts": {
32 | "b": "CONTEXT=$(pwd) npm explore begin-build -- npm run",
33 | "start": "npm run b start:client",
34 | "build": "rm -rf docs && npm run b build",
35 | "dist:rollup": "NODE_OPTIONS=--max_old_space_size=8192 rollup --config",
36 | "dist:uglify": "uglifyjs dist/umd.js -c -m -o dist/umd.min.js",
37 | "dist": "BABEL_ENV=dist rm -rf lib dist && npm run dist:rollup && npm run dist:uglify",
38 | "test": "BABEL_ENV=test ava src/**/test.js",
39 | "test:watch": "BABEL_ENV=test npm run test -- -w",
40 | "test:tap": "BABEL_ENV=test npm run test -- --tap"
41 | },
42 | "peerDependencies": {
43 | "vue": "^2.2.0",
44 | "@babylonjs/core": "^4.0.3",
45 | "@babylonjs/loaders": "^4.0.3"
46 | },
47 | "devDependencies": {
48 | "@babel/core": "^7.4.5",
49 | "@babel/plugin-external-helpers": "^7.0.0",
50 | "@babel/plugin-transform-runtime": "^7.4.4",
51 | "@babel/preset-env": "^7.4.5",
52 | "@babel/register": "^7.4.4",
53 | "@babel/runtime": "^7.4.5",
54 | "@babylonjs/core": "^4.0.3",
55 | "@babylonjs/inspector": "^4.0.3",
56 | "@babylonjs/loaders": "^4.0.3",
57 | "@vue/test-utils": "^1.0.0-beta.25",
58 | "ava": "^2.0.0",
59 | "begin-build": "^0.16.15",
60 | "begin-project": "^0.4.3",
61 | "cannon": "^0.6.2",
62 | "earcut": "^2.1.3",
63 | "eslint-plugin-vue": "^5.0.0-beta.3",
64 | "find": "^0.2.9",
65 | "frow": "^3.1.3",
66 | "glslify-loader": "^2.0.0",
67 | "jstransformer-markdown-it": "^2.1.0",
68 | "jstransformer-pug": "^0.3.0",
69 | "markdown-it-prism": "^2.0.2",
70 | "oimo": "^1.0.9",
71 | "prismjs": "^1.16.0",
72 | "raw-loader": "^1.0.0",
73 | "rollup": "^1.13.1",
74 | "rollup-plugin-babel": "^4.0.3",
75 | "rollup-plugin-cleanup": "^3.0.0",
76 | "rollup-plugin-commonjs": "^10.0.0",
77 | "rollup-plugin-node-resolve": "^5.0.1",
78 | "uglify-js": "^3.6.0"
79 | },
80 | "ava": {
81 | "require": [
82 | "@babel/register"
83 | ]
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/properties.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | production: {
5 | build: {
6 | domain: 'beg-in.github.io',
7 | main: './site/index.js',
8 | cdn: 'https://beg-in.github.io/vue-babylonjs/',
9 | root: 'https://beg-in.github.io/vue-babylonjs/',
10 | title: 'Vue-BabylonJS Documentation site',
11 | color: '#42b883',
12 | dist: 'docs',
13 | config() {
14 | let prism = require('prismjs');
15 | let loadLanguages = require('prismjs/components/index');
16 | let basic = require('begin-build/config/basic');
17 | let vue = require('begin-build/config/vue');
18 | let path = require('path');
19 |
20 | return Object.assign({}, basic, {
21 | local() {
22 | loadLanguages(['pug', 'bash']);
23 | let hl = (text, { lang = 'markup' } = {}) => {
24 | if (text[0] === '\n') {
25 | text = text.substring(1);
26 | }
27 | return `${prism.highlight(text, prism.languages[lang], lang)}
`;
28 | };
29 |
30 | return {
31 | module: {
32 | rules: {
33 | $build: Array,
34 | scripts: {
35 | exclude: /node_modules\/(?!(begin-|@babylonjs))/,
36 | },
37 | markup: {
38 | use: {
39 | $build: Array,
40 | pug: {
41 | options: {
42 | filters: {
43 | hl,
44 | },
45 | data: {
46 | hl,
47 | },
48 | },
49 | },
50 | },
51 | },
52 | shaders: {
53 | test: /\.(glsl|frag|vert)$/,
54 | use: {
55 | $build: Array,
56 | raw: 'raw-loader',
57 | glsl: 'glslify-loader',
58 | },
59 | },
60 | },
61 | },
62 | resolve: {
63 | alias: {
64 | 'vue-babylonjs$': path.join(__dirname, 'src/index.js'),
65 | },
66 | },
67 | };
68 | },
69 | vue,
70 | });
71 | },
72 | },
73 | },
74 | };
75 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import resolve from 'rollup-plugin-node-resolve';
3 | import commonjs from 'rollup-plugin-commonjs';
4 | import cleanup from 'rollup-plugin-cleanup';
5 | // import { fileSync as find } from 'find';
6 |
7 | const name = 'VueBabylonjs';
8 | const plugins = [
9 | resolve(),
10 | babel({
11 | runtimeHelpers: true,
12 | plugins: ['@babel/plugin-external-helpers', '@babel/plugin-transform-runtime'],
13 | ignore: ['node_modules/!(@babylonjs)'],
14 | }),
15 | commonjs({
16 | include: 'node_modules/**',
17 | }),
18 | cleanup(),
19 | ];
20 | // const FILES = find(/.*\/.+\/.+\.js$/, './src').reduce((out, file) => ({
21 | // ...out,
22 | // [file.replace(/src\//, '').replace(/\.js$/, '')]: file,
23 | // }), {});
24 |
25 | export default [{
26 | input: 'src/index.js',
27 | output: {
28 | format: 'es',
29 | file: 'dist/esm.js',
30 | },
31 | external: [
32 | '@babylonjs/core',
33 | '@babylonjs/loaders',
34 | ],
35 | plugins,
36 | }, {
37 | input: 'src/full.js',
38 | output: {
39 | format: 'umd',
40 | name,
41 | file: 'dist/umd.js',
42 | },
43 | plugins,
44 | // }, {
45 | // input: {
46 | // index: 'src/core.js',
47 | // ...FILES,
48 | // },
49 | // experimentalCodeSplitting: true,
50 | // output: {
51 | // format: 'cjs',
52 | // dir: './lib',
53 | // globals,
54 | // },
55 | // plugins,
56 | }];
57 |
--------------------------------------------------------------------------------
/site/.eslintrc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('begin-project/lint/client');
4 | module.exports.rules['import/no-unresolved'] = ['error', { commonjs: true, caseSensitive: true, ignore: ['vue-babylonjs$'] }];
5 |
--------------------------------------------------------------------------------
/site/CNAME:
--------------------------------------------------------------------------------
1 | vuebabylonjs.com
2 |
--------------------------------------------------------------------------------
/site/about.md:
--------------------------------------------------------------------------------
1 |
2 | #### What?
3 | Vue-BabylonJS is a 3D graphics component plugin for Vue.js powered by BabylonJS. Vue-BabylonJS draws inspiration from A-Frame, but can be more performant with the exclusion of DOM manipulation and has closer ties to JavaScript through property binding syntax in Vue. Compared to ReactVR which uses A-Frame, Vue-BabylonJS has the potential for higher performance, more organized and decoupled components, and a higher-quality rendering engine.
4 |
5 |
6 |
7 | #### Why?
8 |
9 | We use BabylonJS because it is the most efficient, most feature-rich, and most modern WebGL graphics library available. The addition of Vue makes the engine reactive and development becomes easier to reason about and organize. Out-of-the-box mobile support and sensible defaults make getting started a breeze.
10 |
11 | The underlying engine is easily accessible to give pros the tools to tweak every aspect of BabylonJS. The organizational structure of the library is a Component-Entity-System and the Entity component contains many powerful features such a matrix transformation to allow for interaction with the Scene graph like a group of HTML divs. Powerful tools are available such as an integrated reactive property system that enables modifying 3D objects within templates and a Shader component that makes adding WebGL shaders easy.
12 |
--------------------------------------------------------------------------------
/site/about.vue:
--------------------------------------------------------------------------------
1 |
2 | article
3 | h2 About
4 | .frow.gutters
5 | .col-md-1-2
6 | .frow
7 | img.founder-image(src="./assets/brian.jpg" alt="Brian")
8 | .founder-name Brian Jesse
9 | a.founder-twitter(href="https://twitter.com/Brain_Bacon") @Brain_Bacon
10 | .founder-title Founder
11 | .links
12 | a(href="https://github.com/Beg-in/vue-babylonjs") GitHub
13 | a(href="https://github.com/Beg-in/vue-babylonjs/issues/1") Updates / Newsletter
14 | a(href="https://github.com/Beg-in/vue-babylonjs/blob/master/CHANGELOG.md") Changelog
15 | a(href="https://github.com/Beg-in/vue-babylonjs/blob/master/CONTRIBUTING.md") Contributing
16 | a(href="https://beg.in/") From Begin
17 | .col-md-1-2
18 | include:markdown-it(plugins=['markdown-it-prism']) ./about.md
19 |
20 |
54 |
--------------------------------------------------------------------------------
/site/animation.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Animations
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/animations/fullscreen")
20 | Example
21 | h5(slot="filename") animation.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/animation.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/animation.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/animation/docs.md
28 |
29 |
--------------------------------------------------------------------------------
/site/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 | #viewport.height-100.width-100
22 | .frow.visible-sm.visible-xs
23 | .hamburger(@click.prevent="sidebar = !sidebar" type="button")
24 | div
25 | div
26 | div
27 | h1 Vue-BabylonJS
28 | .frow.width-100
29 | .col-md-1-5.height-100(:class="{ 'sidebar-hidden': !sidebar }")
30 | .sidebar
31 | nav.height-100(@click="sidebar = false")
32 | .hidden-sm.hidden-xs
33 | h1
34 | router-link(to="/home") Vue-BabylonJS
35 | ul
36 | li
37 | .folder-name Introduction
38 | router-link(tag="li" to="/home")
39 | a Home
40 | router-link(tag="li" to="/installation")
41 | a Installation
42 | router-link(tag="li" to="/about")
43 | a About
44 | li
45 | .folder-name API
46 | router-link(tag="li" to="/animation")
47 | a Animation
48 | router-link(tag="li" to="/asset")
49 | a Asset
50 | router-link(tag="li" to="/camera")
51 | a Camera
52 | router-link(tag="li" to="/entity")
53 | a Entity
54 | router-link(tag="li" to="/light")
55 | a Light
56 | router-link(tag="li" to="/material")
57 | a Material
58 | router-link(tag="li" to="/mesh")
59 | a Mesh
60 | router-link(tag="li" to="/observable")
61 | a Observable
62 | router-link(tag="li" to="/physics")
63 | a Physics
64 | router-link(tag="li" to="/property")
65 | a Property
66 | router-link(tag="li" to="/scene")
67 | a Scene
68 | router-link(tag="li" to="/shader")
69 | a Shader
70 | router-link(tag="li" to="/texture")
71 | a Texture
72 | router-link(tag="li" to="/types")
73 | a Types
74 | .frow
75 | external.github-logo(href="https://github.com/Beg-in/vue-babylonjs") #[Logo]
76 | p © {{new Date().getFullYear()}} Brian Jesse
77 | .col-md-4-5.height-100(:class="{ 'sidebar-hidden': sidebar }")
78 | main
79 | router-view
80 |
81 |
82 |
182 |
--------------------------------------------------------------------------------
/site/asset.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Asset
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/asset/fullscreen")
20 | Example
21 | h5(slot="filename") asset.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/asset.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/asset.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/asset/docs.md
28 |
29 |
--------------------------------------------------------------------------------
/site/assets/brian.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Beg-in/vue-babylonjs/1b8b93cea2368bc3a289fa3d30f41c2c62db673c/site/assets/brian.jpg
--------------------------------------------------------------------------------
/site/assets/github.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/site/camera.vue:
--------------------------------------------------------------------------------
1 |
2 | article
3 | h2 Camera
4 | include:markdown-it(plugins=['markdown-it-prism']) ../src/camera/docs.md
5 |
6 |
--------------------------------------------------------------------------------
/site/controls.vue:
--------------------------------------------------------------------------------
1 |
29 |
30 |
31 | .controls.shadow-dark
32 | .frow
33 | .col-xs-1-1
34 | .controls-container
35 | button.toggle-code(@click="isCodeVisible = !isCodeVisible" type="button") {{ `${isCodeVisible ? 'Hide' : 'Show' } Code` }}
36 | router-link(:to="route")
37 | button.full-screen(v-show="inline" type="button") Full Screen
38 | slot
39 | .col-xs-1-1(v-show="isCodeVisible")
40 | .code-controls
41 | .frow.justify-start
42 | button.code-html-button(@click="isPug = false" type="button" :disabled="!isPug") HTML
43 | button.code-pug-button(@click="isPug = true" type="button" :disabled="isPug") Pug
44 | .code-container
45 | .name-container
46 | slot(name="filename")
47 | .file-container
48 | VueFile(:pug="isPug")
49 | template(slot="vuepug")
50 | slot(name="pug")
51 | template(slot="vuehtml")
52 | slot(name="html")
53 | template(v-if="$slots.script" slot="vuescript")
54 | slot(name="script")
55 | .name-container
56 | slot(name="filename2")
57 | .file-container
58 | VueFile(v-if="$slots.pug2" :pug="isPug")
59 | template(slot="vuepug")
60 | slot(name="pug2")
61 | template(slot="vuehtml")
62 | slot(name="html2")
63 | template(v-if="$slots.script2" slot="vuescript")
64 | slot(name="script2")
65 |
66 |
67 |
121 |
--------------------------------------------------------------------------------
/site/entity.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Entity
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/entity/fullscreen")
20 | Example
21 | h5(slot="filename") entity.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/entity.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/entity.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/entity/docs.md
28 |
29 |
--------------------------------------------------------------------------------
/site/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Beg-in/vue-babylonjs/1b8b93cea2368bc3a289fa3d30f41c2c62db673c/site/favicon.png
--------------------------------------------------------------------------------
/site/global.sass:
--------------------------------------------------------------------------------
1 | @import ./variables
2 | @import ~frow
3 |
4 | html, body
5 | margin: 0
6 | padding: 0
7 | height: 100%
8 | font-family: "Tajawal"
9 | color: $dark-color
10 | background-color: $light-color
11 |
12 | h1, h2, h3, h4
13 | color: $dark-color
14 | font-weight: 700
15 | h1, h2, h3, h4, h5, p
16 | margin-bottom: 24px
17 | padding: 0
18 | h1
19 | font-size: 36px
20 | h2
21 | font-size: 26px
22 | margin: 24px 0 6px
23 | h3
24 | font-size: 24px
25 | h4
26 | font-size: 20px
27 | h5
28 | font-size: 18px
29 |
30 | a
31 | color: $main-color
32 | margin: 0
33 | padding: 0
34 | vertical-align: baseline
35 |
36 | ul
37 | list-style-type: disc
38 | padding-left: 15px
39 | li
40 | line-height: 24px
41 | ul
42 | margin-left: 24px
43 | p, ul, ol
44 | font-size: 16px
45 | line-height: 24px
46 |
47 | pre
48 | padding: 0px 24px
49 | max-width: 800px
50 | white-space: pre-wrap
51 | code
52 | font-family: Consolas, Monaco, Andale Mono, monospace
53 | line-height: 1.5
54 | font-size: 13px
55 | margin-bottom: 24px
56 | *:not(pre) > &
57 | background-color: $background-color
58 | color: $third-color
59 | padding: 1px 5px
60 | margin: 0
61 |
62 | hr
63 | width: 100%
64 | text-align: left
65 | margin: 20px auto 20px 0
66 | color: $secondary-color
67 |
68 | canvas
69 | display: block
70 | &:focus
71 | outline: none
72 |
73 | table
74 | border-collapse: collapse
75 | margin: 1rem 0
76 | display: block
77 | overflow-x: auto
78 |
79 | thead
80 | display: table-header-group
81 | vertical-align: middle
82 | border-color: inherit
83 |
84 | tr
85 | display: table-row
86 | vertical-align: inherit
87 | border-color: inherit
88 |
89 | &:nth-child(2n)
90 | background-color: #f6f8fa
91 |
92 |
93 | th
94 | font-weight: bold
95 | text-align: -internal-center
96 |
97 | td, th
98 | border: 1px solid #dfe2e5
99 | padding: .6em 1em
100 |
101 | tbody
102 | display: table-row-group
103 | vertical-align: middle
104 | border-color: inherit
105 |
--------------------------------------------------------------------------------
/site/highlight.sass:
--------------------------------------------------------------------------------
1 | @import ./variables
2 |
3 | code
4 | border-radius: 3px
5 | background: $base
6 |
7 | pre code
8 | display: block
9 | overflow-x: auto
10 | padding: 0.5em
11 | color: $mono-1
12 | background: $base
13 |
14 | .token.comment,
15 | .token.prolog,
16 | .token.doctype,
17 | .token.cdata
18 | color: slategray
19 |
20 | .token.punctuation
21 | color: #999
22 |
23 | .namespace
24 | opacity: .7
25 |
26 | .token.property,
27 | .token.tag,
28 | .token.boolean,
29 | .token.number,
30 | .token.constant,
31 | .token.symbol,
32 | .token.deleted
33 | color: #905
34 |
35 | .token.selector,
36 | .token.attr-name,
37 | .token.string,
38 | .token.char,
39 | .token.builtin,
40 | .token.inserted
41 | color: #690
42 |
43 | .token.operator,
44 | .token.entity,
45 | .token.url,
46 | .language-css .token.string,
47 | .style .token.string
48 | color: #9a6e3a
49 | background: hsla(0, 0%, 100%, .5)
50 |
51 | .token.atrule,
52 | .token.attr-value,
53 | .token.keyword
54 | color: #07a
55 |
56 | .token.function,
57 | .token.class-name
58 | color: #DD4A68
59 |
60 | .token.regex,
61 | .token.important,
62 | .token.variable
63 | color: #e90
64 |
65 | .token.important,
66 | .token.bold
67 | font-weight: bold
68 |
69 | .token.italic
70 | font-style: italic
71 |
72 | .token.entity
73 | cursor: help
74 |
75 | // .hljs-comment,
76 | // .hljs-quote
77 | // color: $mono-3
78 | // font-style: italic
79 |
80 | // .hljs-doctag,
81 | // .hljs-keyword,
82 | // .hljs-formula
83 | // color: $hue-3
84 |
85 | // .hljs-section,
86 | // .hljs-name,
87 | // .hljs-selector-tag,
88 | // .hljs-deletion,
89 | // .hljs-subst
90 | // color: $hue-5
91 |
92 | // .hljs-literal
93 | // color: $hue-1
94 |
95 | // .hljs-string,
96 | // .hljs-regexp,
97 | // .hljs-addition,
98 | // .hljs-attribute,
99 | // .hljs-meta-string
100 | // color: $hue-4
101 |
102 | // .hljs-built_in,
103 | // .hljs-class .hljs-title
104 | // color: $hue-6-2
105 |
106 | // .hljs-attr,
107 | // .hljs-variable,
108 | // .hljs-template-variable,
109 | // .hljs-type,
110 | // .hljs-selector-class,
111 | // .hljs-selector-attr,
112 | // .hljs-selector-pseudo,
113 | // .hljs-number
114 | // color: $hue-6
115 |
116 | // .hljs-symbol,
117 | // .hljs-bullet,
118 | // .hljs-link,
119 | // .hljs-meta,
120 | // .hljs-selector-id,
121 | // .hljs-title
122 | // color: $hue-2
123 |
124 | // .hljs-emphasis
125 | // font-style: italic
126 |
127 | // .hljs-strong
128 | // font-weight: bold
129 |
130 | // .hljs-link
131 | // text-decoration: underline
132 |
--------------------------------------------------------------------------------
/site/home.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | Controls(:inline="true" route="/home/fullscreen")
16 | Example
17 | h5(slot="filename") logo.vue
18 | pre(slot="pug")
19 | include:hl(lang="pug") ../examples/logo.pug
20 | pre(slot="html")
21 | include:hl:pug(pretty=true) ../examples/logo.pug
22 | h5(slot="filename2") side.vue
23 | pre(slot="pug2")
24 | include:hl(lang="pug") ../examples/side.pug
25 | pre(slot="html2")
26 | include:hl:pug(pretty=true) ../examples/side.pug
27 |
28 | include:markdown-it(plugins=['markdown-it-prism'] html=true) ../src/docs.md
29 |
30 |
--------------------------------------------------------------------------------
/site/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-unresolved, import/no-webpack-loader-syntax, import/first */
2 | import 'file-loader?name=CNAME!./CNAME';
3 | import Vue from 'vue';
4 | import build from 'begin-build';
5 | import { create, register } from 'begin-build/router';
6 | import vb from 'vue-babylonjs';
7 |
8 | Vue.use(vb);
9 |
10 | import app from './app.vue';
11 |
12 | let router = create({
13 | mode: 'hash',
14 | base: '/vue-babylonjs/',
15 | });
16 |
17 | export default build({
18 | router,
19 | components: { app },
20 | });
21 |
22 | import home from './home.vue';
23 | import installation from './installation.vue';
24 | import animation from './animation.vue';
25 | import camera from './camera.vue';
26 | import entity from './entity.vue';
27 | import light from './light.vue';
28 | import material from './material.vue';
29 | import mesh from './mesh.vue';
30 | import observable from './observable.vue';
31 | import physics from './physics.vue';
32 | import property from './property.vue';
33 | import scene from './scene.vue';
34 | import shader from './shader.vue';
35 | import texture from './texture.vue';
36 | import types from './types.vue';
37 | import about from './about.vue';
38 | import asset from './asset.vue';
39 |
40 | register([
41 | ...Object.entries({
42 | home,
43 | installation,
44 | asset,
45 | animation,
46 | camera,
47 | entity,
48 | light,
49 | material,
50 | mesh,
51 | observable,
52 | physics,
53 | property,
54 | scene,
55 | shader,
56 | texture,
57 | types,
58 | about,
59 | }).map(([name, component]) => ({
60 | name,
61 | path: `/${name}`,
62 | component,
63 | })), {
64 | path: '*',
65 | redirect: '/home',
66 | },
67 | ]);
68 |
--------------------------------------------------------------------------------
/site/index.pug:
--------------------------------------------------------------------------------
1 | extends ~begin-build/index.pug
2 |
3 | append meta
4 | meta(name="description", content="Create 3D / VR graphics as simply as writing HTML and CSS")
5 | link(rel="alternate" type="application/rss+xml" href="https://github.com/Beg-in/vue-babylonjs/releases.atom")
6 | link(href="https://fonts.googleapis.com/css?family=Tajawal:300,400,700" rel="stylesheet")
7 |
--------------------------------------------------------------------------------
/site/installation.vue:
--------------------------------------------------------------------------------
1 |
2 | article
3 | h2 Installation
4 | p
5 | h5 Notes:
6 | ul
7 | li Both an NPM package and CDN options are available for installation.
8 | li It is recommended to use the NPM package with a build tool such as #[external(href="https://webpack.js.org/") Webpack] to optimize your usage of the plugin.
9 | li All dependencies (Babylon.js, Earcut, Cannon, and Oimo) are included with the package (minus Vue).
10 | li The global variable exposed by the library is #[code VueBaybylonjs] when using the CDN or UMD package without a module system.
11 | h5 From NPM
12 | pre
13 | :hl(lang="bash")
14 | $ npm install vue-babylonjs
15 | p #[strong or] (using Yarn):
16 | pre
17 | :hl(lang="bash")
18 | $ yarn add vue-babylonjs
19 | p Use the library like this in your script:
20 | pre
21 | :hl(lang="js")
22 | let Vue = require('vue');
23 | Vue.use(require('vue-babylonjs'));
24 | p #[strong or] (Using ES Modules):
25 | pre
26 | :hl(lang="js")
27 | import Vue from 'vue';
28 | import vb from 'vue-babylonjs';
29 | Vue.use(vb);
30 | ul
31 | li The main file provided by this NPM package is a UMD module that will export properly for CommonJS, Web, or AMD environments.
32 | li A module is also provided for ES Module support for the tree-shaking use-case.
33 | li See more in the Usage section below for information on how to leverage tree-shaking with ES Modules.
34 |
35 | p
36 | external(href="https://glitch.com/edit/#!/vue-babylonjs-starter") See the complete starter example on Glitch
37 |
38 | h5 Via CDN
39 | p Get the latest version of Vue-BabylonJS from #[external(href="https://www.jsdelivr.com", title="jsDelivr cdn") jsDelivr]:
40 | pre
41 | code!= hl(``)
42 | p
43 | p When the script has loaded you can use the library in a script like this:
44 | pre
45 | :hl(lang="js")
46 | Vue.use(window.VueBabylonjs);
47 | ul
48 | li The CDN version includes all of the Components available in this library.
49 | li This includes a Physics component that only uses Cannon.js and omits Oimo.js.
50 |
51 | h2 Usage
52 | h5 Basics
53 | p All installation methods can be initialized with the following Vue template
54 | pre
55 | :hl
56 |
57 |
58 |
59 | p #[strong or] (using Pug):
60 | pre
61 | :hl(lang="pug")
62 | Scene
63 | Box(:position="[0, 0, 5]")
64 | h5 Advanced ES Module support
65 | ul
66 | li You can import specific portions of the library to leverage tree-shaking in compatible build tools, e.g. Webpack.
67 | li All components, including the mesh components, are exported individually from the ES Module.
68 | li A special #[code plugin] export contains the installation logic for this plugin without any components.
69 | li The export #[code BABYLON] contains all of the classes exported by Babylon.js.
70 | li The #[code default] export contains installation logic that will include all components, effectively bypassing any tree-shaking functionality.
71 | li The #[code components] option of the installation mechanism also allows for renaming components.
72 | li Physics components are individually exported per their underlying library as #[code Cannon] and #[code Oimo].
73 | p Example usage of cherry-picking components with the ES Module functionality:
74 | pre
75 | :hl(lang="js")
76 | import Vue from 'vue';
77 | import { plugin, Scene, Box, Cannon } from 'vue-babylonjs';
78 | Vue.use(plugin, { components: { Scene, Box, Physics: Cannon } });
79 | p You can also use individual exports as mixins or in specific components:
80 | p Initialization in script:
81 | pre
82 | :hl(lang="js")
83 | import { plugin } from 'vue-babylonjs';
84 | Vue.use(plugin);
85 | p Usage in component:
86 | pre
87 | :hl(lang="js")
88 | import { Entity, Scene, Box } from 'vue-babylonjs';
89 | export default {
90 | mixins: [Entity],
91 | components: { Scene, Box },
92 | };
93 |
94 |
--------------------------------------------------------------------------------
/site/light.vue:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 | article
21 | h2 Light
22 |
23 | h4 Directional Light Demonstration
24 | Controls(:inline="true" route="/light/fullscreen")
25 | DirectionalExample
26 | h5(slot="filename") directional.vue
27 | pre(slot="pug")
28 | include:hl(lang="pug") ../examples/light/directional.pug
29 | pre(slot="html")
30 | include:hl:pug(pretty=true) ../examples/light/directional.pug
31 |
32 | h4 Hemispheric Light Demonstration
33 | p The two boxes below are the same boxes from 'Directional Light Demonstration'.
34 | p Notice that the color changes on all sides of the boxes with hemispheric light.
35 | Controls(:inline="true" route="/light/fullscreen")
36 | HemisphericExample
37 | h5(slot="filename") hemispheric.vue
38 | pre(slot="pug")
39 | include:hl(lang="pug") ../examples/light/hemispheric.pug
40 | pre(slot="html")
41 | include:hl:pug(pretty=true) ../examples/light/hemispheric.pug
42 |
43 | h4 Point Light Demonstration
44 | p Imagine there is a lightbulb between two spheres,
45 | p then the light points to the right side of the left yellow sphere,
46 | p and the light also points to left side of the right green sphere.
47 | Controls(:inline="true" route="/light/fullscreen")
48 | PointExample
49 | h5(slot="filename") point.vue
50 | pre(slot="pug")
51 | include:hl(lang="pug") ../examples/light/point.pug
52 | pre(slot="html")
53 | include:hl:pug(pretty=true) ../examples/light/point.pug
54 |
55 | //- SPOTLIGHT
56 | //- h4 Spot Light Demonstration
57 | //- br
58 | //- br
59 | //- Controls(:inline="true" route="/light/fullscreen")
60 | //- SpotExample
61 | //- h5(slot="filename") spot.vue
62 | //- pre(slot="pug")
63 | //- include:hl(lang="pug") ../examples/light/spot.pug
64 | //- pre(slot="html")
65 | //- include:hl:pug(pretty=true) ../examples/light/spot.pug
66 |
67 | include:markdown-it(plugins=['markdown-it-prism']) ../src/light/docs.md
68 |
69 |
--------------------------------------------------------------------------------
/site/material.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Material
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/material/fullscreen")
20 | Example
21 | h5(slot="filename") material.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/material.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/material.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/material/docs.md
28 |
29 |
30 |
--------------------------------------------------------------------------------
/site/mesh.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 | article
17 | h2 Mesh
18 |
19 | h4 Example
20 |
21 | Controls(:inline="true" route="mesh/fullscreen")
22 | MeshExample
23 | h5(slot="filename") mesh.vue
24 | pre(slot="pug")
25 | include:hl(lang="pug") ../examples/mesh.pug
26 | pre(slot="html")
27 | include:hl:pug(pretty=true) ../examples/mesh.pug
28 |
29 | p All Shapes Inherit from Entity Component
30 | Controls(:inline="true" route="scale/fullscreen")
31 | ScaleExample
32 | h5(slot="filename") scale.vue
33 | pre(slot="pug")
34 | include:hl(lang="pug") ../examples/scale.pug
35 | pre(slot="html")
36 | include:hl:pug(pretty=true) ../examples/scale.pug
37 |
38 | include:markdown-it(plugins=['markdown-it-prism']) ../src/mesh/docs.md
39 |
40 |
--------------------------------------------------------------------------------
/site/observable.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Observable
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/observable/fullscreen")
20 | Example
21 | h5(slot="filename") observable.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/observable.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/observable.pug
26 | pre(slot="script")
27 | include:hl(lang="javascript") ../examples/observable.js
28 |
29 | include:markdown-it(plugins=['markdown-it-prism']) ../src/observable/docs.md
30 |
31 |
--------------------------------------------------------------------------------
/site/physics.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Physics
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/physics/fullscreen")
20 | Example
21 | h5(slot="filename") physics.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/physics.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/physics.pug
26 | pre(slot="script")
27 | include:hl(lang="javascript") ../examples/physics.js
28 |
29 | include:markdown-it(plugins=['markdown-it-prism']) ../src/physics/docs.md
30 |
31 |
--------------------------------------------------------------------------------
/site/property.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Property
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/property/fullscreen")
20 | Example
21 | h5(slot="filename") properties.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/property.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/property.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/property/docs.md
28 |
29 |
--------------------------------------------------------------------------------
/site/scene.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Scene
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/scene/fullscreen")
20 | Example
21 | h5(slot="filename") scene.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/scene.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/scene.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/scene/docs.md
28 |
29 |
--------------------------------------------------------------------------------
/site/shader.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Shader
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/shader/fullscreen")
20 | Example
21 | h5(slot="filename") shader.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/shader.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/shader.pug
26 | pre(slot="script")
27 | include:hl(lang="javascript") ../examples/shader.js
28 |
29 | include:markdown-it(plugins=['markdown-it-prism']) ../src/shader/docs.md
30 |
31 |
--------------------------------------------------------------------------------
/site/texture.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | article
15 | h2 Texture
16 |
17 | h4 Example
18 |
19 | Controls(:inline="true" route="/animations/fullscreen")
20 | Example
21 | h5(slot="filename") texture.vue
22 | pre(slot="pug")
23 | include:hl(lang="pug") ../examples/texture.pug
24 | pre(slot="html")
25 | include:hl:pug(pretty=true) ../examples/texture.pug
26 |
27 | include:markdown-it(plugins=['markdown-it-prism']) ../src/texture/docs.md
28 |
29 |
--------------------------------------------------------------------------------
/site/types.vue:
--------------------------------------------------------------------------------
1 |
2 | article
3 | h2 Types
4 | include:markdown-it(plugins=['markdown-it-prism']) ../src/types/docs.md
5 |
6 |
--------------------------------------------------------------------------------
/site/variables.sass:
--------------------------------------------------------------------------------
1 | $light-color: #ffffff
2 | $dark-color: #333333
3 | $main-color: #42b883
4 | $secondary-color: #35495e
5 | $background-color: #f8f8f8
6 | $third-color: #e96900
7 |
8 | $button-background-color: $main-color
9 | $button-border-color: $main-color
10 | // $button-disabled-text-color: $gray-light
11 | $button-disabled-border-color: $dark-color
12 |
13 | $form-color-primary: $main-color
14 | $form-color-secondary: $secondary-color
15 |
16 | // Highlight colors
17 | $base: #fafafa
18 | $mono-1: #383a42
19 | $mono-2: #686b77
20 | $mono-3: #a0a1a7
21 | $hue-1: #0184bb
22 | $hue-2: #4078f2
23 | $hue-3: #a626a4
24 | $hue-4: #50a14f
25 | $hue-5: #e45649
26 | $hue-5-2: #c91243
27 | $hue-6: #986801
28 | $hue-6-2: #c18401
29 |
30 | @import ~frow/variables
31 |
--------------------------------------------------------------------------------
/site/vuefile.pug:
--------------------------------------------------------------------------------
1 | .vuefile
2 | code(v-show="pug")
3 | :hl
4 | code(v-show="!pug")
5 | :hl
6 | code(v-show="pug")
7 | slot(name="vuepug")
8 | code(v-show="!pug")
9 | slot(name="vuehtml")
10 | :hl
11 | code(v-if="$slots.vuescript")
12 | br
13 | :hl
18 |
--------------------------------------------------------------------------------
/site/vuefile.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
27 |
--------------------------------------------------------------------------------
/src/animation/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | This component will apply an animation to an Entity component
4 |
5 | #### Details
6 |
7 | The [BabylonJS guide to animations](http://doc.babylonjs.com/babylon101/animations) can be helpful here.
8 |
9 | - Must be a child component of an existing Entity
10 | - Properties are in the format `myObject.myProperty`
11 |
12 | See [the BabylonJS api documentation on the Animation class](http://doc.babylonjs.com/api/classes/babylon.animation)
13 |
14 | #### Usage
15 |
16 | ```html
17 |
18 |
19 |
24 |
25 |
26 |
27 | ```
28 |
29 | #### Props
30 |
31 | - `type` (String) - The type of property to animate, see below for valid values:
32 | - `"float"`
33 | - `"vector2"`
34 | - `"vector3"`
35 | - `"size"`
36 | - `"quaternion"`
37 | - `"matrix"`
38 | - `"color3"`
39 | - `mode` (String) - The loop mode of the animation, see below for valid values:
40 | - `"cycle"`
41 | - `"relative"`
42 | - `"constant"`
43 | - `property` (String) - Path to the property to animate with dots (`.`)
44 | - `fps` (Number) - the frames-per-second of the animation (default 60)
45 | - `from` (Number) - Frame number to begin animating on
46 | - `to` (Number) - Frame number to end animating on
47 | - `duration` (Number) - Length of the animation in seconds
48 | - `start` (Number) - Starting value of the property that is being animated
49 | - `end` (Number) - Ending value of the property that is being animated
50 | - `loop` (Boolean) - Whether to loop the animation (default true)
51 | - `speedRatio` (Number) - The speed ratio of this animation
52 | - `animatable` (Object) - A specific animation object from BabylonJS
53 | - `blending` (Boolean) - enable interpolation FROM the current object's state (default false)
54 | - `blendingSpeed` (Number) - speed of blending interpolation
55 | - `easing` (String) - easing function name, see below for valid values:
56 | - `"circle"`
57 | - `"back"`
58 | - `"bounce"`
59 | - `"cubic"`
60 | - `"elastic"`
61 | - `"exponential"`
62 | - `"power"`
63 | - `"quadratic"`
64 | - `"quartic"`
65 | - `"quintic"`
66 | - `"sine"`
67 | - `"bezierCurve"`
68 | - `easingMode` (String) - mode of the easing function, see below for valid values:
69 | - `"in"`
70 | - `"out"`
71 | - `"inout"`
72 | - `amplitude` (Number) - For the `"back"` easing function
73 | - `bounces` (Number) - For the `"bounce"` easing function
74 | - `bounciness` (Number) - For the `"bounce"` easing function
75 | - `oscillations` (Number) - For the `"elastic"` easing function
76 | - `springiness` (Number) - For the `"elastic"` easing function
77 | - `exponent` (Number) - For the `"exponential"` easing function
78 | - `power` (Number) - For the `"power"` easing function
79 | - `x1` (Number) - For the `"bezierCurve"` easing function
80 | - `y1` (Number) - For the `"bezierCurve"` easing function
81 | - `x2` (Number) - For the `"bezierCurve"` easing function
82 | - `y2` (Number) - For the `"bezierCurve"` easing function
83 |
84 | ### Key
85 |
86 | This component represents a keyframe for an Animation component
87 |
88 | #### Details
89 |
90 | - Must be a child component of an existing Animation component
91 |
92 | #### Usage
93 |
94 | ```html
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | ```
105 |
106 | #### Props
107 |
108 | - `frame` (Number|String) - what frame number this keyframe represents or a string percentage (`XX%`) of the duration
109 | - `value` (any) - the value to set the property to at this keyframe
110 | - `inTangent` (Vector3) - Optional spline interpolation mode
111 | - `outTangent` (Vector3) - Optional spline interpolation mode
112 |
--------------------------------------------------------------------------------
/src/animation/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | EasingFunction,
3 | Animation,
4 | CircleEase as circle,
5 | BackEase as back,
6 | BounceEase as bounce,
7 | CubicEase as cubic,
8 | ElasticEase as elastic,
9 | ExponentialEase as exponential,
10 | PowerEase as power,
11 | QuadraticEase as quadratic,
12 | QuarticEase as quartic,
13 | QuinticEase as quintic,
14 | SineEase as sine,
15 | BezierCurveEase as bezierCurve,
16 | } from '@babylonjs/core';
17 | import AbstractEntity from '../entity/abstract';
18 | import { isFloat } from '../util';
19 |
20 | const EASINGS = {
21 | circle,
22 | back,
23 | bounce,
24 | cubic,
25 | elastic,
26 | exponential,
27 | power,
28 | quadratic,
29 | quartic,
30 | quintic,
31 | sine,
32 | bezierCurve,
33 | };
34 | const TYPES = {
35 | FLOAT: 'float',
36 | VECTOR2: 'vector2',
37 | VECTOR3: 'vector3',
38 | SIZE: 'size',
39 | QUATERNION: 'quaternion',
40 | MATRIX: 'matrix',
41 | COLOR3: 'color3',
42 | };
43 | const MODES = {
44 | CYCLE: 'cycle',
45 | RELATIVE: 'relative',
46 | CONSTANT: 'constant',
47 | };
48 | const EASING_MODES = {
49 | IN: 'in',
50 | OUT: 'out',
51 | INOUT: 'inout',
52 | };
53 |
54 | export default {
55 | mixins: [AbstractEntity],
56 |
57 | data() {
58 | return {
59 | keys: {},
60 | };
61 | },
62 |
63 | props: {
64 | type: {
65 | validator: value => Object.values(TYPES).includes(value),
66 | default: Object.values(TYPES)[0],
67 | },
68 |
69 | mode: {
70 | validator: value => Object.values(MODES).includes(value),
71 | default: Object.values(MODES)[0],
72 | },
73 |
74 | property: {
75 | type: String,
76 | },
77 |
78 | fps: {
79 | type: Number,
80 | default: 60,
81 | },
82 |
83 | from: {
84 | type: Number,
85 | default: 0,
86 | },
87 |
88 | to: {
89 | type: Number,
90 | default: 60,
91 | },
92 |
93 | duration: {
94 | type: Number,
95 | default: null,
96 | },
97 |
98 | start: {
99 | default: 0,
100 | },
101 |
102 | end: {
103 | default: 1,
104 | },
105 |
106 | loop: {
107 | type: Boolean,
108 | default: true,
109 | },
110 |
111 | speedRatio: {
112 | type: Number,
113 | default: 1,
114 | },
115 |
116 | animatable: {
117 | type: Object,
118 | default: null,
119 | },
120 |
121 | blending: {
122 | type: Boolean,
123 | default: false,
124 | },
125 |
126 | blendingSpeed: {
127 | type: Number,
128 | default: null,
129 | },
130 |
131 | easing: {
132 | validator: value => Object.values(EASINGS).includes(value),
133 | default: null,
134 | },
135 |
136 | easingMode: {
137 | validator: value => Object.values(EASING_MODES).includes(value),
138 | default: Object.values(EASING_MODES)[0],
139 | },
140 |
141 | amplitude: {
142 | type: Number,
143 | default: 1,
144 | },
145 |
146 | bounces: {
147 | type: Number,
148 | default: 3,
149 | },
150 |
151 | bounciness: {
152 | type: Number,
153 | default: 2,
154 | },
155 |
156 | oscillations: {
157 | type: Number,
158 | default: 3,
159 | },
160 |
161 | springiness: {
162 | type: Number,
163 | default: 3,
164 | },
165 |
166 | exponent: {
167 | type: Number,
168 | default: 2,
169 | },
170 |
171 | power: {
172 | type: Number,
173 | default: 2,
174 | },
175 |
176 | x1: {
177 | type: Number,
178 | default: 0.32,
179 | },
180 |
181 | y1: {
182 | type: Number,
183 | default: -0.73,
184 | },
185 |
186 | x2: {
187 | type: Number,
188 | default: 0.69,
189 | },
190 |
191 | y2: {
192 | type: Number,
193 | default: 1.59,
194 | },
195 | },
196 |
197 | computed: {
198 | easingFunction() {
199 | if (!this.easing) {
200 | return null;
201 | }
202 | let easing = EASINGS[this.easing];
203 | let easingFunction;
204 | switch (this.easing) {
205 | case 'back':
206 | easingFunction = easing(this.amplitude);
207 | break;
208 | case 'bounce':
209 | easingFunction = easing(this.bounces, this.bounciness);
210 | break;
211 | case 'elastic':
212 | easingFunction = easing(this.oscillations, this.springiness);
213 | break;
214 | case 'exponential':
215 | easingFunction = easing(this.exponent);
216 | break;
217 | case 'power':
218 | easingFunction = easing(this.power);
219 | break;
220 | case 'bezierCurve':
221 | easingFunction = easing(this.x1, this.y1, this.x2, this.y2);
222 | break;
223 | default:
224 | easingFunction = easing();
225 | }
226 | easingFunction.setEasingMode(EasingFunction[`EASINGMODE_EASE${
227 | this.easingMode.toUpperCase()
228 | }`]);
229 | return easingFunction;
230 | },
231 |
232 | finish() {
233 | return this.duration ? this.duration * this.fps : this.to;
234 | },
235 |
236 | frames() {
237 | let keys = Object.values(this.keys);
238 | if (keys.length < 1) {
239 | return [{
240 | frame: this.from,
241 | value: this.start,
242 | }, {
243 | frame: this.finish,
244 | value: this.end,
245 | }];
246 | }
247 | return keys.map(key => {
248 | let frame = Number.parseFloat(key.frame);
249 | if (!isFloat(key.frame)) {
250 | frame = Math.floor((frame / 100) * this.finish);
251 | }
252 | let out = {
253 | frame,
254 | value: key.value,
255 | };
256 | if (key.outTangent) {
257 | out.outTangent = key.outTangent;
258 | }
259 | if (key.inTangent) {
260 | out.inTangent = key.inTangent;
261 | }
262 | return out;
263 | });
264 | },
265 |
266 | animationType() {
267 | return Animation[`ANIMATIONTYPE_${this.type.toUpperCase()}`];
268 | },
269 |
270 | animationLoopMode() {
271 | return Animation[`ANIMATIONLOOPMODE_${this.mode.toUpperCase()}`];
272 | },
273 | },
274 |
275 | methods: {
276 | enableBlending(speed) {
277 | this.$entity.enableBlending(speed);
278 | },
279 |
280 | disableBlending() {
281 | this.$entity.disableBlending();
282 | },
283 |
284 | setEasingFunction() {
285 | this.$entity.setEasingFunction(this.easingFunction);
286 | },
287 |
288 | setFrames() {
289 | if (this.$entity) {
290 | this.$entity.setKeys(this.frames);
291 | }
292 | },
293 | },
294 |
295 | watch: {
296 | fps() {
297 | this.$entity.framePerSecond = this.fps;
298 | },
299 |
300 | property() {
301 | this.$entity.targetProperty = this.property;
302 | },
303 |
304 | animationType() {
305 | this.dataType = this.animationType;
306 | },
307 |
308 | animationLoopMode() {
309 | this.loopMode = this.animationLoopMode;
310 | },
311 |
312 | frames() {
313 | this.setFrames();
314 | },
315 |
316 | easingFunction() {
317 | this.setEasingFunction();
318 | },
319 |
320 | speedRatio() {
321 | this.$entity.speedRatio = this.speedRatio;
322 | },
323 |
324 | loop() {
325 | this.$entity.loopAnimation = this.loop;
326 | },
327 |
328 | blending() {
329 | if (this.blending) {
330 | this.enableBlending(this.blendingSpeed);
331 | } else {
332 | this.disableBlending();
333 | }
334 | },
335 | },
336 |
337 | events: {
338 | setKey({ name, key }) {
339 | this.$set(this.keys, name, key);
340 | },
341 |
342 | removeKey(name) {
343 | this.$delete(this.keys, name);
344 | },
345 |
346 | reset() {
347 | this.$entity.stop();
348 | },
349 |
350 | enableBlending(speed) {
351 | this.enableBlending(speed);
352 | },
353 |
354 | disableBlending() {
355 | this.disableBlending();
356 | },
357 |
358 | goToFrame(frame) {
359 | this.$entity.goToFrame(frame);
360 | },
361 |
362 | pause() {
363 | this.$entity.pause();
364 | },
365 |
366 | restart() {
367 | this.$entity.restart();
368 | },
369 |
370 | stop() {
371 | this.$entity.stop();
372 | },
373 | },
374 |
375 | onScene({ name }) {
376 | return new Animation(name, this.property, this.fps, this.animationType, this.animationLoopMode);
377 | },
378 |
379 | onParent({ parent, entity, scene }) {
380 | this.setEasingFunction();
381 | this.setFrames();
382 | parent.animations.push(entity);
383 | scene.beginAnimation(parent, this.from, this.finish, this.loop, this.speedRatio, () => {
384 | this.$event.$emit('end');
385 | }, this.animatable);
386 | },
387 | };
388 |
--------------------------------------------------------------------------------
/src/animation/key.js:
--------------------------------------------------------------------------------
1 | import AbstractEntity from '../entity/abstract';
2 | import { isFloat, isPercent } from '../util';
3 | import { vec3 } from '../types/vector';
4 |
5 | const { validator } = vec3;
6 |
7 | export default {
8 | mixins: [AbstractEntity],
9 |
10 | props: {
11 | frame: {
12 | validator: value => isFloat(value) || isPercent(value),
13 | default: 0,
14 | },
15 |
16 | value: {
17 | default: 0,
18 | },
19 |
20 | inTangent: {
21 | validator,
22 | default: null,
23 | },
24 |
25 | outTangent: {
26 | validator,
27 | default: null,
28 | },
29 | },
30 |
31 | computed: {
32 | key() {
33 | return {
34 | frame: this.frame,
35 | value: this.value,
36 | inTangent: this.inTangent,
37 | outTangent: this.outTangent,
38 | };
39 | },
40 | },
41 |
42 | methods: {
43 | setKey() {
44 | this.$bus.$emit('setKey', {
45 | name: this.name,
46 | key: this.key,
47 | });
48 | },
49 |
50 | dispose() {
51 | this.$bus.$emit('disposeKey', this.name);
52 | },
53 | },
54 |
55 | watch: {
56 | key() {
57 | this.setKey();
58 | },
59 | },
60 |
61 | created() {
62 | this.setKey();
63 | },
64 |
65 | beforeDestroy() {
66 | this.dispose();
67 | },
68 | };
69 |
--------------------------------------------------------------------------------
/src/api.js:
--------------------------------------------------------------------------------
1 | export { $vector } from './types/vector';
2 | export { $color } from './types/color';
3 | export { $matrix } from './types/matrix';
4 |
--------------------------------------------------------------------------------
/src/asset/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Load an asset file from a URL location
4 |
5 | #### Details
6 |
7 | The BabylonJS [guide to loading files](https://doc.babylonjs.com/how_to/load_from_any_file_type) can be helpful here.
8 |
9 | - Creates a root mesh for all of the assets contained inside the referred file
10 |
11 | #### Usage
12 |
13 | ```html
14 |
15 |
16 |
17 | ```
18 |
19 | #### Props
20 |
21 | - `src` (String) - url path to an asset file of type `gltf`, `obj`, `stl`, or `babylon`
22 |
--------------------------------------------------------------------------------
/src/asset/index.js:
--------------------------------------------------------------------------------
1 | import '@babylonjs/loaders';
2 | import { SceneLoader } from '@babylonjs/core';
3 | import Entity from '../entity';
4 |
5 | export default {
6 | mixins: [Entity],
7 |
8 | props: {
9 | src: {
10 | type: String,
11 | default: null,
12 | },
13 | },
14 |
15 | watch: {
16 | src() {
17 | this.loadAssetContainer();
18 | },
19 | },
20 |
21 | methods: {
22 | async loadAssetContainer() {
23 | if (!this.src) {
24 | return;
25 | }
26 | await this._$_sceneReady;
27 | let assetContainer = await SceneLoader.LoadAssetContainerAsync(this.src);
28 | await this._$_parentReady;
29 | if (assetContainer.meshes.length > 1) {
30 | this.$replace(assetContainer.createRootMesh());
31 | } else {
32 | this.$replace(assetContainer.meshes[0]);
33 | }
34 | assetContainer.addAllToScene();
35 | },
36 | },
37 |
38 | mounted() {
39 | this.loadAssetContainer();
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/src/camera/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | This component will define a camera in a scene
4 |
5 | #### Details
6 |
7 | The [BabylonJS guide to cameras](https://doc.babylonjs.com/babylon101/cameras) can be helpful here.
8 |
9 | - Can be defined anywhere as a descendant of the Scene component
10 | - Can be transformed (moved/rotated) by using a parent Entity
11 |
12 | #### Usage
13 |
14 | ```html
15 |
16 |
17 |
18 | ```
19 |
20 | #### Props
21 |
22 | - `type` (String) - The type of camera to use, see below for valid values:
23 | - `"universal"`
24 | - `"free"`
25 | - `"follow"`
26 | - `"arcRotate"`
27 | - `"arcFollow"`
28 | - `"deviceOrientation"`
29 | - `"touch"`
30 | - `"gamepad"`
31 | - `position` (Vector3) - Starting position for the camera
32 | - `target` (Vector3) - Targets the camera to a particular position
33 | - `alpha` (Number) - alpha (radians) the longitudinal rotation for `"arcRotate"` and `"arcFollow"` type cameras
34 | - `beta` (Number) - beta (radians) the latitudinal rotation for `"arcRotate"` and `"arcFollow"` type cameras
35 | - `radius` (Number) - The distance from the target for `"arcRotate"` and `"arcFollow"` type cameras
36 |
--------------------------------------------------------------------------------
/src/camera/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | Vector3,
3 | UniversalCamera as universal,
4 | FreeCamera as free,
5 | FollowCamera as follow,
6 | ArcRotateCamera as arcRotate,
7 | ArcFollowCamera as arcFollow,
8 | DeviceOrientationCamera as deviceOrientation,
9 | TouchCamera as touch,
10 | GamepadCamera as gamepad,
11 | } from '@babylonjs/core';
12 | import AbstractEntity from '../entity/abstract';
13 | import { vec3, toVec3 } from '../types/vector';
14 |
15 | const TYPES = {
16 | universal,
17 | free,
18 | follow,
19 | arcRotate,
20 | arcFollow,
21 | deviceOrientation,
22 | touch,
23 | gamepad,
24 | };
25 |
26 | export default {
27 | mixins: [AbstractEntity],
28 |
29 | inject: ['EngineReady'],
30 |
31 | props: {
32 | type: {
33 | validator: value => Object.keys(TYPES).includes(value),
34 | default: Object.keys(TYPES)[0],
35 | },
36 |
37 | position: {
38 | validator: vec3.validator,
39 | default: () => new Vector3(0, 0, -10),
40 | },
41 |
42 | target: vec3,
43 |
44 | alpha: {
45 | type: Number,
46 | default: -Math.PI / 2,
47 | },
48 |
49 | beta: {
50 | type: Number,
51 | default: Math.PI / 2,
52 | },
53 |
54 | radius: {
55 | type: Number,
56 | default: 10,
57 | },
58 | },
59 |
60 | computed: {
61 | positionVector3() {
62 | return toVec3(this.position);
63 | },
64 |
65 | targetVector3() {
66 | return toVec3(this.target);
67 | },
68 |
69 | args() {
70 | let out = [this.name];
71 | if (this.type === 'arcRotate' || this.type === 'arcFollow') {
72 | out = out.concat([this.alpha, this.beta, this.radius, this.targetVector3]);
73 | } else {
74 | out = out.concat([this.positionVector3]);
75 | }
76 | return out.concat([this.$scene]);
77 | },
78 | },
79 |
80 | methods: {
81 | attachControl() {
82 | this.$entity.attachControl(this.canvas);
83 | },
84 |
85 | detachControl() {
86 | this.$entity.detachControl();
87 | },
88 |
89 | create() {
90 | if (this.$entity) {
91 | this.detachControl();
92 | delete this.$entity.onDispose;
93 | this.$entity.dispose();
94 | }
95 | this.$entity = new TYPES[this.type](...this.args);
96 | this.$entity.onDispose = () => {
97 | this.detachControl();
98 | if (!this._$_destroyed) {
99 | this.$destroy();
100 | }
101 | };
102 | },
103 | },
104 |
105 | watch: {
106 | type() {
107 | this.create();
108 | },
109 |
110 | position() {
111 | this.$entity.position.copyFrom(this.positionVector3);
112 | },
113 |
114 | target() {
115 | this.$entity.setTarget(this.targetVector3);
116 | },
117 |
118 | alpha() {
119 | this.$entity.alpha = this.alpha;
120 | },
121 |
122 | beta() {
123 | this.$entity.beta = this.beta;
124 | },
125 |
126 | radius() {
127 | this.$entity.radius = this.radius;
128 | },
129 | },
130 |
131 | events: {
132 | attachControl() {
133 | this.attachControl();
134 | },
135 |
136 | detachControl() {
137 | this.detachControl();
138 | },
139 | },
140 |
141 | async onScene({ scene }) {
142 | this.canvas = scene.getEngine().getRenderingCanvas();
143 | this.create();
144 | this.attachControl();
145 | return this.$entity;
146 | },
147 |
148 | beforeDestroy() {
149 | this._$_destroyed = true;
150 | if (this.$entity && this.$entity.dispose) {
151 | this.$entity.dispose();
152 | }
153 | },
154 | };
155 |
--------------------------------------------------------------------------------
/src/core.js:
--------------------------------------------------------------------------------
1 | // import earcut from 'earcut';
2 | import * as api from './api';
3 |
4 | export const install = (Vue, { components = {} } = {}) => {
5 | // if (!window.earcut) {
6 | // window.earcut = earcut;
7 | // }
8 | Object.assign(Vue.prototype, api);
9 | Object.assign(Vue, api);
10 | Object.entries(components).forEach(entry => Vue.component(...entry));
11 | };
12 |
13 | export * from './api';
14 |
--------------------------------------------------------------------------------
/src/docs.md:
--------------------------------------------------------------------------------
1 | ## Vue-BabylonJS helps you create high quality 3D graphics in the web.
2 | ## It's as easy as writing HTML and CSS.
3 |
4 |
5 |
6 | ---
7 |
8 | #### Vue-BabylonJS is a powerful tool. You can create 3D graphics featuring:
9 | - Physics
10 | - Lighting Properties
11 | - Cameras
12 | - Textures or Materials
13 | - More (See Sidebar)
14 |
15 | ---
16 |
17 |
18 | # **Get Started**
19 |
20 |
21 | ## Installation:
22 | See instructions page
23 |
24 | ## Usage:
25 |
26 | ## Important things to know
27 |
28 | - **All components of this library must be a descendant of the Scene Component.**
29 | - Many components expect to be a child of specific components defined by this plugin, check the API documentation of the component to see what its requirements are
30 |
31 | ### Types for props (attributes)
32 |
33 | **Vue bindings are important when using this plugin**
34 |
35 | Always use `v-bind:property` or the shorthand `:property` on attributes to components that expect non-string values!
36 |
37 | The following BabylonJS types have specific helpers in this plugin:
38 |
39 | - `Color3` and `Color4` as a unified `Color` API
40 | - `Vector2`, `Vector3`, and `Vector4` as a unified `Vector` API
41 | - `Matrix`
42 |
43 | See the documentation for Types for more information
44 |
45 | ### Retrieving BabylonJS Objects
46 |
47 | Most components in this plugin support Vue's model-binding syntax.
48 |
49 | #### Notes
50 |
51 | - Use the attribute `v-model` on components
52 | - `v-model` does not require binding syntax
53 | - bind it to a property in your data object
54 | - Use `null` for your initial value in your data object
55 | - The model will not be immediately available, so do not expect populated data in lifecycle hooks
56 | - Use a watch function to be notified when the data property is populated and initeract with the object from there
57 | - The `v-model` value on some components may change during the lifecycle of the scene, so plan your watchers accordingly
58 |
59 | #### Example
60 |
61 | ##### Template:
62 |
63 | ```html
64 |
65 |
66 |
67 |
68 |
69 | ```
70 |
71 | ##### Script:
72 |
73 | ```js
74 | module.exports = {
75 | data() {
76 | return {
77 | myScene: null,
78 | myEntity: null,
79 | myBox: null,
80 | };
81 | },
82 |
83 | watch: {
84 | myScene() {
85 | // myScene is now available from the component
86 | // do something with it here or call a method to use it from here
87 | },
88 |
89 | myEntity() {
90 | // myEntity is now available from the component
91 | // do something with it here or call a method to use it from here
92 | },
93 |
94 | myBox() {
95 | // myBox is now available from the component
96 | // do something with it here or call a method to use it from here
97 | },
98 | },
99 | };
100 | ```
101 |
102 | See the Entity documentation for more information
103 |
--------------------------------------------------------------------------------
/src/entity/abstract.js:
--------------------------------------------------------------------------------
1 | import { id, isDisposable, createBus, defer } from '../util';
2 | import { registerObservers } from '../observable';
3 |
4 | export default {
5 | inject: {
6 | _$_sceneReady: 'SceneReady',
7 |
8 | _$_parentReady: {
9 | from: 'EntityReady',
10 | default: Promise.resolve(null),
11 | },
12 |
13 | $bus: {
14 | from: 'EntityBus',
15 | default() {
16 | return createBus.call(this);
17 | },
18 | },
19 |
20 | $sceneBus: {
21 | from: 'SceneBus',
22 | default() {
23 | return createBus.call(this);
24 | },
25 | },
26 | },
27 |
28 | provide() {
29 | return {
30 | EntityReady: this._$_entityReady,
31 | EntityBus: this.$event,
32 | };
33 | },
34 |
35 | model: {
36 | prop: '_$_input',
37 | event: '_$_output',
38 | },
39 |
40 | props: {
41 | _$_input: {
42 | type: Object,
43 | default: null,
44 | },
45 |
46 | name: {
47 | type: String,
48 | default: id,
49 | },
50 |
51 | properties: {
52 | type: Object,
53 | default: null,
54 | },
55 | },
56 |
57 | methods: {
58 | _$_applyProperties() {
59 | if (this.$entity && this.properties) {
60 | Object.assign(this.$entity, this.properties);
61 | }
62 | },
63 |
64 | async _$_init() {
65 | this._$_clearObservers = registerObservers.call(this, this.$scene);
66 | if (this.$options._$_onTransform) { // Private Lifecycle Hook
67 | await this.$options._$_onTransform.call(this);
68 | }
69 | if (this.$options.onEntity) { // Lifecycle Hook
70 | await this.$options.onEntity.call(this, this._$_hookArgs);
71 | }
72 | if (isDisposable(this.$entity)) {
73 | this.$entity.onDispose = () => {
74 | if (!this._$_destroyed) {
75 | this.$destroy();
76 | }
77 | };
78 | }
79 | this.$emit('_$_output', this.$entity);
80 | this.$event.$emit('change', this.$entity);
81 | this.$emit('entity', this._$_hookArgs);
82 | },
83 |
84 | async _$_onParent(parent) {
85 | this._$_parent = parent;
86 | this._$_hookArgs.parent = this._$_parent;
87 | if (this.$options.onParent) { // Lifecycle Hook
88 | await this.$options.onParent.call(this, this._$_hookArgs);
89 | }
90 | this.$emit('parent', this._$_hookArgs);
91 | },
92 |
93 | async $replace(entity) {
94 | if (this._$_clearObservers) {
95 | this._$_clearObservers();
96 | }
97 | if (isDisposable(this.$entity)) {
98 | this._$_destroyed = true;
99 | this.$entity.dispose();
100 | this._$_destroyed = false;
101 | }
102 | this.$entity = entity;
103 | await this._$_init();
104 | },
105 |
106 | register({ name }) {
107 | this._$_children[name] = defer();
108 | },
109 |
110 | complete({ name, entity }) {
111 | this._$_children[name].complete({ name, entity });
112 | },
113 | },
114 |
115 | watch: {
116 | properties: {
117 | handler() {
118 | this._$_applyProperties();
119 | },
120 | deep: true,
121 | },
122 |
123 | _$_input() {
124 | if (this.$entity !== this._$_input) {
125 | this.$replace(this._$_input);
126 | }
127 | },
128 | },
129 |
130 | beforeCreate() {
131 | this.$event = createBus.call(this);
132 | this._$_entityReady = defer();
133 | },
134 |
135 | created() {
136 | this._$_hookArgs = {
137 | name: this.name,
138 | };
139 | if (this.$options.events) {
140 | Object.entries(this.$options.events).forEach(([name, fn]) => {
141 | this.$event.$on(name, fn.bind(this));
142 | });
143 | }
144 | },
145 |
146 | beforeMount() {
147 | this._$_children = {};
148 | this.$event.$on('register', this.register);
149 | this.$event.$on('complete', this.complete);
150 | this.$bus.$emit('register', { name: this.name });
151 | },
152 |
153 | async mounted() {
154 | if (this.$options.beforeScene) { // Lifecycle Hook
155 | this.$entity = await this.$options.beforeScene.call(this, Object.assign({
156 | sceneReady: this._$_sceneReady,
157 | parentReady: this._$_parentReady,
158 | }, this._$_hookArgs));
159 | }
160 | this.$scene = await this._$_sceneReady;
161 | this._$_hookArgs.scene = this.$scene;
162 | let sceneArgs = Object.assign({
163 | parentReady: this._$_parentReady,
164 | }, this._$_hookArgs);
165 | this.$emit('scene', sceneArgs);
166 | if (this.$options.onScene) { // Lifecycle Hook
167 | this.$entity = await this.$options.onScene.call(this, sceneArgs);
168 | }
169 | this._$_hookArgs.entity = this.$entity;
170 | this._$_onParent(await this._$_parentReady);
171 | this.$bus.$on('change', this._$_onParent.bind(this));
172 | if (this._$_input) {
173 | this.$replace(this._$_input);
174 | } else {
175 | await this._$_init();
176 | }
177 | if (this.$options.beforeRender) { // Render Loop Hook
178 | this._$_beforeRender = this.$options.beforeRender.bind(this);
179 | this.$scene.registerBeforeRender(this._$_beforeRender);
180 | }
181 | if (this.$options.afterRender) { // Render Loop Hook
182 | this._$_afterRender = this.$options.afterRender.bind(this);
183 | this.$scene.registerAfterRender(this._$_afterRender);
184 | }
185 | this._$_entityReady.complete(this.$entity);
186 | this.$bus.$emit('complete', { name: this.name, entity: this.$entity });
187 | this._$_applyProperties();
188 | let children = await Promise.all(Object.values(this._$_children));
189 | children = children.reduce((out, { name, entity }) => {
190 | out[name] = entity;
191 | return out;
192 | }, {});
193 | this._$_hookArgs.children = children;
194 | this.$emit('complete', this._$_hookArgs);
195 | },
196 |
197 | beforeDestroy() {
198 | this._$_destroyed = true;
199 | if (this._$_clearObservers) {
200 | this._$_clearObservers();
201 | }
202 | this.$emit('dispose');
203 | if (isDisposable(this.$entity)) {
204 | this.$entity.dispose();
205 | }
206 | if (this._$_beforeRender) {
207 | this.$scene.unregisterBeforeRender(this._$_beforeRender);
208 | }
209 | if (this._$_afterRender) {
210 | this.$scene.unregisterAfterRender(this._$_afterRender);
211 | }
212 | },
213 |
214 | render(createElement) {
215 | return createElement('div', this.$slots.default);
216 | },
217 | };
218 |
--------------------------------------------------------------------------------
/src/entity/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | The basic Entity component to manipulate and transform the scene with
4 |
5 | #### Details
6 |
7 | - Use Entity as if it were an HTML `div` to manipulate and group child components
8 |
9 | #### Usage
10 |
11 | ```html
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ```
20 |
21 | #### Events
22 | - `scene` - When the parent scene object is available
23 | - `parent` - When the parent entity is available
24 | - `entity` - When the underlying BabylonJS object is available
25 | - `complete` - When all child entities are available
26 | - `dispose` - When this Entity has been scheduled for disposal
27 | - All observables from `Scene` and the underlying BabylonJS object, see the Observable documentation for details
28 |
29 | #### Props
30 |
31 | - `name` (String) - The unique name to give an entity in BabylonJS (automatic random uid if not defined)
32 | - `position` (Vector3) - The position vector in 3D space relative to the parent
33 | - `rotation` (Vector3) - The rotation vector (in radians) relative to the parent
34 | - `scaling` (Vector3) - The scaling vector that will stretch/compress this entity and its children
35 | - `properties` (Object) - Other properties to set on the underlying BabylonJS object if not available as a prop (attribute)
36 |
37 | ##### Mixin functionality:
38 |
39 | - The Entity component can be used as a Vue mixin, `import Entity from 'vue-babylonjs';` to use it in this manner
40 | - The default Entity mixin includes transform properties like `position`, `rotation`, and `scaling`, use `import AbstractEntity from 'vue-babylonjs';` instead to omit this functionality
41 | - When using `AbstractEntity` as a mixin, be sure to call `this.$replace(entity)` to set the Entity's underlying BabylonJS object
42 | - In the source code, methods and variables with a leading underscore (`_`) are marked "private" and are not guaranteed to remain or function the same in future versions of the plugin
43 | - Most components, if not all indirectly, inherit from Entity through this mixin functionality
44 | - To better understand this functionality it can be helpful to read the source code of the other components defined in this plugin
45 | - Most other components in this library can also be used as a mixin, but their property and function names may conflict with your names, when in doubt check the source code of the component you are mixing in
46 | - See `src/mixins.js` to see what components are available to mixin
47 |
48 | Public properties:
49 |
50 | - `$entity` - A reference to the underlying BabylonJS object for this Entity
51 | - `$scene` - A reference to the root Scene BabylonJS object
52 | - `$bus` - A Vue event bus to pass events to the parent Entity
53 | - `$event` - A Vue event bus to pass events to the children of this component (becomes that child's `$bus`)
54 |
55 | Public methods:
56 |
57 | - `$replace` - set the value of this Entity's `$entity` (the underlying BabylonJS object in most cases)
58 |
59 | Custom Lifecycle Hooks:
60 |
61 | - Lifecycle hooks are functions bound to a `this` context of the Entity component
62 | - These functions can be `async` or return a Promise to resolve asynchronously
63 | - The following are public lifecycle hook functions:
64 | - `beforeScene` - called before the Scene is finished initializing or immediately when the Scene exists
65 | - `onScene` - called immediately after the Scene is initialized
66 | - `onParent` - called after the parent Entity is resolved
67 | - `onEntity` - called after this Entity's underlying `$entity` is resolved
68 | - `beforeRender` - called before every frame renders
69 | - `afterRender` - called after every frame renders
70 | - These functions are passed a single object containing references to variables used at that stage of the Entity lifecycle, the object will have the following properties:
71 | - `name` - a reference to this Entity's unique `name` value (always available)
72 | - `scene` - a reference to the root Scene object from BabylonJS (available during and after `onScene`)
73 | - `parent` - a reference to the parent Entity's `$entity` (available during and after `onParent`)
74 | - `entity` - a reference to the underlying `$entity` object (available during and after `onEntity`)
75 | - **Warning** lifecycle hook functions do not merge when mixed in like native Vue lifecycle events
76 |
77 | Custom Event Hooks:
78 |
79 | - Optionally if a `events` object is defined in the component then functions defined within will be called on events with names matching the properties of this object
80 | - This is for events fired on the `$event` bus from the children of this Entity
81 | - Functions defined within will be passed a single object conatining the value passed from the event
82 | - **Warning** the properties defined within `events` will not be merged if used as a mixin
83 |
--------------------------------------------------------------------------------
/src/entity/index.js:
--------------------------------------------------------------------------------
1 | import { Vector3, MeshBuilder } from '@babylonjs/core';
2 | import AbstractEntity from '../entity/abstract';
3 | import { vec3, toVec3 } from '../types/vector';
4 |
5 | const { validator } = vec3;
6 |
7 | export default {
8 | mixins: [AbstractEntity],
9 |
10 | props: {
11 | position: vec3,
12 | rotation: vec3,
13 | scaling: {
14 | validator,
15 | default: () => Vector3.One(),
16 | },
17 | },
18 |
19 | computed: {
20 | _$_positionVector3() {
21 | return toVec3(this.position);
22 | },
23 |
24 | _$_rotationVector3() {
25 | return toVec3(this.rotation);
26 | },
27 |
28 | _$_scalingVector3() {
29 | return toVec3(this.scaling);
30 | },
31 | },
32 |
33 | watch: {
34 | _$_positionVector3() {
35 | this._$_setPosition();
36 | },
37 |
38 | _$_rotationVector3() {
39 | this._$_setRotation();
40 | },
41 |
42 | _$_scalingVector3() {
43 | this._$_setScaling();
44 | },
45 | },
46 |
47 | methods: {
48 | _$_setPosition() {
49 | if (this.$entity && this.$entity.position) {
50 | this.$entity.position.copyFrom(this._$_positionVector3);
51 | }
52 | },
53 |
54 | _$_setRotation() {
55 | if (this.$entity && this.$entity.rotation) {
56 | this.$entity.rotation.copyFrom(this._$_rotationVector3);
57 | }
58 | },
59 |
60 | _$_setScaling() {
61 | if (this.$entity && this.$entity.scaling) {
62 | this.$entity.scaling.copyFrom(this._$_scalingVector3);
63 | }
64 | },
65 | },
66 |
67 | created() {
68 | Object.assign(this._$_hookArgs, {
69 | position: this._$_positionVector3,
70 | rotation: this._$_rotationVector3,
71 | scaling: this._$_scalingVector3,
72 | });
73 | },
74 |
75 | /* eslint-disable camelcase */
76 | _$_onTransform() {
77 | if (!this.$entity) {
78 | // HACK: TransformNode does not implement IPhysicsEnabledObject, so using invisible box instead
79 | let box = MeshBuilder.CreateBox(this.name, {}, this.$scene);
80 | box.isVisible = false;
81 | this.$entity = box;
82 | }
83 | this._$_setPosition();
84 | this._$_setRotation();
85 | this._$_setScaling();
86 | if (!this.$entity.parent) {
87 | this.$entity.parent = this._$_parent;
88 | }
89 | },
90 | };
91 |
--------------------------------------------------------------------------------
/src/full.js:
--------------------------------------------------------------------------------
1 | import * as BABYLON from '@babylonjs/core';
2 | import { install as init } from './core';
3 | import { Cannon as Physics } from './physics';
4 | import * as mixins from './mixins';
5 |
6 | export function install(Vue, options = {}) {
7 | Object.assign(Vue.prototype, { BABYLON });
8 | Object.assign(Vue, { BABYLON });
9 | init(Vue, Object.assign({ components: Object.assign({ Physics }, mixins) }, options));
10 | }
11 |
12 | export { BABYLON };
13 | export * from './api';
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import * as BABYLON from '@babylonjs/core';
2 | import * as plugin from './core';
3 | import * as full from './full';
4 |
5 | export default full;
6 | export { BABYLON, plugin };
7 | export { default as AbstractEntity } from './entity/abstract';
8 | export * from './mixins';
9 | export * from './core';
10 | export * from './physics';
11 |
--------------------------------------------------------------------------------
/src/light/directional.js:
--------------------------------------------------------------------------------
1 | import { DirectionalLight } from '@babylonjs/core';
2 | import AbstractLight from './';
3 | import { vec3, toVec3 } from '../types/vector';
4 |
5 | export default {
6 | mixins: [AbstractLight],
7 |
8 | props: {
9 | direction: vec3,
10 | },
11 |
12 | computed: {
13 | directionVector3() {
14 | return toVec3(this.direction);
15 | },
16 | },
17 |
18 | watch: {
19 | directionVector3() {
20 | this.setDirection();
21 | },
22 | },
23 |
24 | methods: {
25 | setDirection() {
26 | this.$entity.direction.copyFrom(this.directionVector3);
27 | },
28 | },
29 |
30 | onScene({ name, scene }) {
31 | return new DirectionalLight(name, this.directionVector3, scene);
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/src/light/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Define lighting in a scene
4 |
5 | #### Components
6 |
7 | - DirectionalLight
8 | - HemisphericLight
9 | - PointLight
10 | - SpotLight
11 |
12 | #### Details
13 |
14 | The [BabylonJS guide to lights](https://doc.babylonjs.com/babylon101/lights) can be helpful here.
15 |
16 | - Can be defined anywhere as a descendant of the Scene component
17 | - Can be transformed (position) with an ancestor Entity component
18 |
19 | #### Usage
20 |
21 | ```html
22 |
23 |
24 |
25 |
26 |
27 |
28 | ```
29 |
30 | #### Props
31 |
32 | All Lights:
33 |
34 | - `diffuse` (Color3) - Gives the basic color to an object
35 | - `specular` (Color3) - Produces a highlight color on an object
36 |
37 | DirectionalLight, HemisphericLight, and SpotLight:
38 |
39 | - `direction` (Vector3) - direction of the light
40 |
41 | SpotLight:
42 |
43 | - `angle` (Number) - in radians, defines the size (field of illumination) of the spotlight's conical beam
44 | - `exponent` (Number) - defines the speed of the decay of the light with distance (reach)
45 |
--------------------------------------------------------------------------------
/src/light/hemispheric.js:
--------------------------------------------------------------------------------
1 | import { HemisphericLight } from '@babylonjs/core';
2 | import DirectionalLight from './directional';
3 |
4 | export default {
5 | mixins: [DirectionalLight],
6 |
7 | onScene({ name, scene }) {
8 | return new HemisphericLight(name, this.directionVector3, scene);
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/src/light/index.js:
--------------------------------------------------------------------------------
1 | import { color3, toColor3 } from '../types/color';
2 | import Entity from '../entity';
3 |
4 | export default {
5 | mixins: [Entity],
6 |
7 | props: {
8 | diffuse: color3,
9 | specular: color3,
10 | },
11 |
12 | computed: {
13 | diffuseColor3() {
14 | return toColor3(this.diffuse);
15 | },
16 |
17 | specularColor3() {
18 | return toColor3(this.specular);
19 | },
20 | },
21 |
22 | watch: {
23 | diffuseColor3() {
24 | this.setDiffuse();
25 | },
26 |
27 | specularColor3() {
28 | this.setSpecular();
29 | },
30 | },
31 |
32 | methods: {
33 | setDiffuse() {
34 | this.$entity.diffuse.copyFrom(this.diffuseColor3);
35 | },
36 |
37 | setSpecular() {
38 | this.$entity.specular.copyFrom(this.specularColor3);
39 | },
40 | },
41 |
42 | onEntity() {
43 | this.setDiffuse();
44 | this.setSpecular();
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/src/light/point.js:
--------------------------------------------------------------------------------
1 | import { PointLight } from '@babylonjs/core';
2 | import AbstractLight from './';
3 |
4 | export default {
5 | mixins: [AbstractLight],
6 |
7 | onScene({ name, position, scene }) {
8 | return new PointLight(name, position, scene);
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/src/light/spot.js:
--------------------------------------------------------------------------------
1 | import { SpotLight } from '@babylonjs/core';
2 | import DirectionalLight from './directional';
3 | import { isFloat } from '../util';
4 |
5 | export default {
6 | mixins: [DirectionalLight],
7 |
8 | props: {
9 | angle: {
10 | validator: isFloat,
11 | default: Math.PI / 2,
12 | },
13 |
14 | exponent: {
15 | validator: isFloat,
16 | default: 1.5,
17 | },
18 | },
19 |
20 | watch: {
21 | angle() {
22 | this.$entity.angle = this.angle;
23 | },
24 |
25 | exponent() {
26 | this.$entity.exponent = this.exponent;
27 | },
28 | },
29 |
30 | onScene({ name, position, scene }) {
31 | return new SpotLight(name, position, this.directionVector3, this.angle, this.exponent, scene);
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/src/material/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Apply a material to a mesh
4 |
5 | #### Details
6 |
7 | The [BabylonJS guide to materials](https://doc.babylonjs.com/babylon101/materials) can be helpful here.
8 |
9 | - Must be a child of a Mesh component
10 | - Both StandardMaterial and PBRMaterial classes are available to use through the Material component
11 | - The component unifies as many properties as possible to make PBRMaterial as easy to use as possible
12 | - When a `glossiness`, `metallic`, or `roughness` property is used, the component will switch to PBRMaterial
13 | - Texture properties can be used on Material using a Texture component
14 |
15 | #### Usage
16 |
17 | ```html
18 |
19 |
20 |
21 |
22 |
23 | ```
24 |
25 | #### Props
26 |
27 | - `diffuse` (Color3) - The basic color of the material as viewed under a light
28 | - `specular` (Color3) - The highlight given to the material by a light
29 | - `emissive` (Color3) - The color of the material as if self lit
30 | - `ambient` (Color3) - The color of the material lit by the environmental background lighting
31 | - `reflection` (Color3) - For PBRMaterial reflection color
32 | - `alpha` (Number) - Transparency of the material
33 | - `metallic` (Number) - For PBRMaterial specifies the metallic scalar value of the material
34 | - `roughness` (Number) - For PBRMaterial specifies the roughness scalar value of the material
35 | - `glossiness` (Number) - For PBRMaterial how sharp the reflection is
36 | - `indexOfRefraction` (Number) - For PBRMaterial index of refraction with transparency
37 |
--------------------------------------------------------------------------------
/src/material/index.js:
--------------------------------------------------------------------------------
1 | import { Color3, StandardMaterial, PBRMaterial } from '@babylonjs/core';
2 | import AbstractEntity from '../entity/abstract';
3 | import { color3, toColor3 } from '../types/color';
4 |
5 | const STANDARD = 'standard';
6 | const PBR = 'pbr';
7 | let { validator } = color3;
8 |
9 | export default {
10 | mixins: [AbstractEntity],
11 |
12 | props: {
13 | diffuse: {
14 | validator,
15 | default: () => new Color3(1, 1, 1),
16 | },
17 |
18 | specular: {
19 | validator,
20 | default: () => new Color3(1, 1, 1),
21 | },
22 |
23 | emissive: {
24 | validator,
25 | default: () => new Color3(0, 0, 0),
26 | },
27 |
28 | ambient: {
29 | validator,
30 | default: () => new Color3(0, 0, 0),
31 | },
32 |
33 | reflection: {
34 | validator,
35 | default: () => new Color3(1, 1, 1),
36 | },
37 |
38 | alpha: {
39 | type: Number,
40 | default: 1,
41 | },
42 |
43 | metallic: {
44 | type: Number,
45 | default: null,
46 | },
47 |
48 | roughness: {
49 | type: Number,
50 | default: null,
51 | },
52 |
53 | glossiness: {
54 | type: Number,
55 | default: null,
56 | },
57 |
58 | indexOfRefraction: {
59 | type: Number,
60 | default: 0.66,
61 | },
62 | },
63 |
64 | computed: {
65 | type() {
66 | if (this.glossiness !== null || this.metallic !== null || this.roughness !== null) {
67 | return PBR;
68 | }
69 | return STANDARD;
70 | },
71 |
72 | diffuseColor3() {
73 | return toColor3(this.diffuse);
74 | },
75 |
76 | specularColor3() {
77 | return toColor3(this.specular);
78 | },
79 |
80 | emissiveColor3() {
81 | return toColor3(this.emissive);
82 | },
83 |
84 | ambientColor3() {
85 | return toColor3(this.ambient);
86 | },
87 |
88 | reflectionColor3() {
89 | return toColor3(this.reflection);
90 | },
91 | },
92 |
93 | methods: {
94 | createMaterial(parent) {
95 | let entity;
96 | if (this.type === PBR) {
97 | if (this.$entity instanceof PBRMaterial) {
98 | return;
99 | }
100 | entity = new PBRMaterial(this.name, this.$scene);
101 | entity.albedoColor = this.diffuseColor3;
102 | entity.reflectivityColor = this.specularColor3;
103 | entity.reflectionColor = this.reflectionColor3;
104 | entity.metallic = this.metallic;
105 | entity.roughness = this.roughness;
106 | entity.microSurface = this.glossiness;
107 | entity.indexOfRefraction = this.indexOfRefraction;
108 | } else {
109 | if (this.$entity instanceof StandardMaterial) {
110 | return;
111 | }
112 | entity = new StandardMaterial(this.name, this.$scene);
113 | entity.diffuseColor = this.diffuseColor3;
114 | entity.specularColor = this.specularColor3;
115 | }
116 | entity.emissiveColor = this.emissiveColor3;
117 | entity.ambientColor = this.ambientColor3;
118 | entity.alpha = this.alpha;
119 | this.$replace(entity);
120 | parent.material = this.$entity;
121 | },
122 |
123 | getTextureName(name) {
124 | if (this.type === STANDARD) {
125 | return name;
126 | }
127 | switch (name) {
128 | case 'baseTexture':
129 | case 'diffuseTexture':
130 | return 'albedoTexture';
131 | case 'metallicRoughnessTexture':
132 | return 'metallicTexture';
133 | case 'environmentTexture':
134 | return 'reflectionTexture';
135 | case 'normalTexture':
136 | return 'bumpTexture';
137 | case 'occlusionTexture':
138 | return 'ambientTexture';
139 | case 'specularGlossinessTexture':
140 | return 'reflectivityTexture';
141 | default:
142 | return name;
143 | }
144 | },
145 | },
146 |
147 | watch: {
148 | type() {
149 | this.createMaterial(this._$_parent);
150 | },
151 |
152 | diffuseColor3() {
153 | if (this.type === PBR) {
154 | this.$entity.albedoColor = this.diffuseColor3;
155 | } else {
156 | this.$entity.diffuseColor = this.diffuseColor3;
157 | }
158 | },
159 |
160 | specularColor3() {
161 | if (this.type === PBR) {
162 | this.$entity.reflectivityColor = this.specularColor3;
163 | } else {
164 | this.$entity.specularColor = this.specularColor3;
165 | }
166 | },
167 |
168 | emissiveColor3() {
169 | this.$entity.emissiveColor = this.emissiveColor3;
170 | },
171 |
172 | ambientColor3() {
173 | this.$entity.ambientColor = this.ambientColor3;
174 | },
175 |
176 | reflectionColor3() {
177 | this.$entity.reflectionColor = this.reflectionColor3;
178 | },
179 |
180 | alpha() {
181 | this.$entity.alpha = this.alpha;
182 | },
183 |
184 | metallic() {
185 | this.$entity.metallic = this.metallic;
186 | },
187 |
188 | roughness() {
189 | this.$entity.roughness = this.roughness;
190 | },
191 |
192 | glossiness() {
193 | this.$entity.microSurface = this.glossiness;
194 | },
195 |
196 | indexOfRefraction() {
197 | this.$entity.indexOfRefraction = this.indexOfRefraction;
198 | },
199 | },
200 |
201 | events: {
202 | setTexture({ property, texture }) {
203 | this.$entity[this.getTextureName(property)] = texture;
204 | },
205 |
206 | disposeTexture({ property }) {
207 | this.$entity[this.getTextureName(property)] = null;
208 | },
209 | },
210 |
211 | onParent({ parent }) {
212 | this.createMaterial(parent);
213 | },
214 | };
215 |
--------------------------------------------------------------------------------
/src/mesh/abstract.js:
--------------------------------------------------------------------------------
1 | import Entity from '../entity';
2 |
3 | export default {
4 | mixins: [Entity],
5 |
6 | props: {
7 | options: {
8 | type: Object,
9 | default: () => ({}),
10 | },
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/src/mesh/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Use `MeshBuilder` to constuct a `Mesh` for basic primitive shapes
4 |
5 | #### Components
6 |
7 | - Box
8 | - Cylinder
9 | - DashedLines
10 | - Disc
11 | - Ground
12 | - IcoSphere
13 | - Lathe
14 | - Lines
15 | - LineSystem
16 | - Plane
17 | - PolygonMesh
18 | - Polyhedron
19 | - Ribbon
20 | - Sphere
21 | - TiledGround
22 | - Torus
23 | - TorusKnot
24 | - Tube
25 | - ExtrudePolygon
26 | - ExtrudeShape
27 | - ExtrudeShapeCustom
28 |
29 | #### Details
30 |
31 | The [BabylonJS guide to basic shapes](https://doc.babylonjs.com/babylon101/discover_basic_elements) can be helpful here.
32 |
33 | - Inherits properties from the Entity component for transform attributes `position`, `rotation`, and `scaling`
34 | - Can be colored by using the Material component as a child of the mesh
35 | - The `Polygon` class from BabylonJS has been renamed to PolygonMesh here since `polygon` is a reserved HTML tag name
36 | - The `options` attribute is non-reactive, create a new mesh instead of manipulating this object (this will change in the future)
37 |
38 | [See the BabylonJS documentaion on the `MeshBuilder` class](https://doc.babylonjs.com/api/classes/babylon.meshbuilder)
39 |
40 | #### Usage
41 |
42 | ```html
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | ```
69 |
70 | #### Props
71 |
72 | - `options` (Object) - options passed to [`MeshBuilder`](https://doc.babylonjs.com/api/classes/babylon.meshbuilder)
73 |
--------------------------------------------------------------------------------
/src/mesh/index.js:
--------------------------------------------------------------------------------
1 | import earcut from 'earcut';
2 | import { MeshBuilder } from '@babylonjs/core';
3 | import AbstractMesh from './abstract';
4 |
5 | const prepare = fn => ({
6 | mixins: [AbstractMesh],
7 |
8 | onScene({ name, scene }) {
9 | return fn(name, this.options, scene, earcut);
10 | },
11 | });
12 |
13 | // TODO: add CreateDecal(name, sourceMesh, options)
14 | // TODO: add CreateGroundFromHeightMap(name, url, options, scene)
15 | export const Box = prepare(MeshBuilder.CreateBox);
16 | export const Cylinder = prepare(MeshBuilder.CreateCylinder);
17 | export const DashedLines = prepare(MeshBuilder.CreateDashedLines);
18 | export const Disc = prepare(MeshBuilder.CreateDisc);
19 | export const Ground = prepare(MeshBuilder.CreateGround);
20 | export const IcoSphere = prepare(MeshBuilder.CreateIcoSphere);
21 | export const Lathe = prepare(MeshBuilder.CreateLathe);
22 | export const Lines = prepare(MeshBuilder.CreateLines);
23 | export const LineSystem = prepare(MeshBuilder.CreateLineSystem);
24 | export const Plane = prepare(MeshBuilder.CreatePlane);
25 | export const PolygonMesh = prepare(MeshBuilder.CreatePolygon);
26 | export const Polyhedron = prepare(MeshBuilder.CreatePolyhedron);
27 | export const Ribbon = prepare(MeshBuilder.CreateRibbon);
28 | export const Sphere = prepare(MeshBuilder.CreateSphere);
29 | export const TiledGround = prepare(MeshBuilder.CreateTiledGround);
30 | export const Torus = prepare(MeshBuilder.CreateTorus);
31 | export const TorusKnot = prepare(MeshBuilder.CreateTorusKnot);
32 | export const Tube = prepare(MeshBuilder.CreateTube);
33 | export const ExtrudePolygon = prepare(MeshBuilder.ExtrudePolygon);
34 | export const ExtrudeShape = prepare(MeshBuilder.ExtrudeShape);
35 | export const ExtrudeShapeCustom = prepare(MeshBuilder.ExtrudeShapeCustom);
36 |
--------------------------------------------------------------------------------
/src/mixins.js:
--------------------------------------------------------------------------------
1 | export { default as Scene } from './scene';
2 | export { default as Camera } from './camera';
3 | export { default as Entity } from './entity';
4 | export { default as Property } from './property';
5 | export { default as Asset } from './asset';
6 | export { default as Material } from './material';
7 | export { default as Texture } from './texture';
8 | export { default as Animation } from './animation';
9 | export { default as Key } from './animation/key';
10 | export { default as DirectionalLight } from './light/directional';
11 | export { default as HemisphericLight } from './light/hemispheric';
12 | export { default as PointLight } from './light/point';
13 | export { default as SpotLight } from './light/spot';
14 | export { default as Shader } from './shader';
15 | export { default as Vertex } from './shader/vertex';
16 | export { default as Fragment } from './shader/fragment';
17 | export { default as Attribute } from './shader/attribute';
18 | export { default as Uniform } from './shader/uniform';
19 | export * from './mesh';
20 |
--------------------------------------------------------------------------------
/src/observable/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Interact with observables exposed by Babylonjs objects
4 |
5 | #### Details
6 |
7 | The [BabylonJS guide to observables](https://doc.babylonjs.com/how_to/observables) and Vue's [custom events documentation](https://vuejs.org/v2/guide/components-custom-events.html) can be helpful here.
8 |
9 | - Components in this libraray expose observable subscribers as integrated with the Vue event system
10 | - Attributes in the form `@some-name$` will become an observer using the `onSomeNameObservable` property on the underlying Babylonjs object.
11 | - The listener will attempt to find a matching observable on the underlying object and in the event that one does not exist will attempt to match one on the parent scene.
12 | - Use the `.once` modifier on the listner attribute to only run the listner function once.
13 | - The implementation is based on custom events within Vue and uses Vue's `$listeners` property to efficiently register subscribers with their associated Observables.
14 |
15 | #### Usage
16 |
17 | For your convenience here is a mapping of listner attribute to BabylonJS Observable on all of the current Scene class observables.
18 |
19 | **Scene observables checked during each renderLoop (in the order they are checked)**
20 |
21 | | Event Prop | Scene Object Observable Name |
22 | | --- | --- |
23 | | `@before-animations$` | onBeforeAnimationsObservable |
24 | | `@after-animations$` | onAfterAnimationsObservable |
25 | | `@before-physics$` | onBeforePhysicsObservable |
26 | | `@after-physics$` | onAfterPhysicsObservable |
27 | | `@before-render$` | onBeforeRenderObservable |
28 | | `@before-render-targets-render$` | onBeforeRenderTargetsRenderObservable |
29 | | `@after-render-targets-render$` | onAfterRenderTargetsRenderObservable |
30 | | `@before-camera-render$` | onBeforeCameraRenderObservable |
31 | | `@before-active-meshes-evaluation$` | onBeforeActiveMeshesEvaluationObservable |
32 | | `@after-active-meshes-evaluation$` | onAfterActiveMeshesEvaluationObservable |
33 | | `@before-particles-rendering$` | onBeforeParticlesRenderingObservable |
34 | | `@after-particles-rendering$` | onAfterParticlesRenderingObservable |
35 | | `@before-draw-phase$` | onBeforeDrawPhaseObservable |
36 | | `@after-draw-phase$` | onAfterDrawPhaseObservable |
37 | | `@after-camera-render$` | onAfterCameraRenderObservable |
38 | | `@after-render$` | onAfterRenderObservable |
39 |
40 | **Other Scene observables**
41 |
42 | | Event Prop | Scene Object Observable Name |
43 | | --- | --- |
44 | | `@before-rendering-group$` | onBeforeRenderingGroupObservable |
45 | | `@after-rendering-group$` | onAfterRenderingGroupObservable |
46 | | `@before-sprites-rendering$` | onBeforeSpritesRenderingObservable |
47 | | `@after-sprites-rendering$` | onAfterSpritesRenderingObservable |
48 | | `@before-step$` | onBeforeStepObservable |
49 | | `@after-step$` | onAfterStepObservable |
50 | | `@new-camera-added$` | onNewCameraAddedObservable |
51 | | `@camera-removed$` | onCameraRemovedObservable |
52 | | `@data-loaded$` | onDataLoadedObservable |
53 | | `@dispose$` | onDisposeObservable |
54 | | `@new-geometry-added$` | onNewGeometryAddedObservable |
55 | | `@geometry-removed$` | onGeometryRemovedObservable |
56 | | `@pre-keyboard$` | onPreKeyboardObservable |
57 | | `@keyboard$` | onKeyboardObservable |
58 | | `@new-light-added$` | onNewLightAddedObservable |
59 | | `@light-removed$` | onLightRemovedObservable |
60 | | `@new-mesh-added$` | onNewMeshAddedObservable |
61 | | `@mesh-removed$` | onMeshRemovedObservable |
62 | | `@new-transform-node-added$` | onNewTransformNodeAddedObservable |
63 | | `@transform-node-removed$` | onTransformNodeRemovedObservable |
64 | | `@pre-pointer$` | onPrePointerObservable |
65 | | `@pointer$` | onPointerObservable |
66 | | `@ready$` | onReadyObservable |
67 |
--------------------------------------------------------------------------------
/src/observable/index.js:
--------------------------------------------------------------------------------
1 | import { Observable } from '@babylonjs/core';
2 | import { camelize, last } from '../util';
3 |
4 | export function registerObservers(scene) {
5 | let observers = Object.keys(this.$listeners).reduce((out, key) => {
6 | let name = key;
7 | let [first, ...rest] = name;
8 | let target = 'add';
9 | if (first === '~') {
10 | target = 'addOnce';
11 | name = rest.join('');
12 | }
13 | name = camelize(name);
14 | key = key.replace('~', '');
15 | if (last(name) === '$') {
16 | name = [...name];
17 | name.pop();
18 | name = name.join('');
19 | name = `on${name}Observable`;
20 | } else {
21 | return out;
22 | }
23 | let observable = null;
24 | if (this.$entity && this.$entity[name] instanceof Observable) {
25 | observable = this.$entity[name];
26 | } else if (scene && scene[name] instanceof Observable) {
27 | observable = scene[name];
28 | } else {
29 | console.warn(`Could not find Observable with name ${name}`)
30 | return out;
31 | }
32 | let observer = null;
33 | if (observable) {
34 | observer = observable[target](() => this.$emit(key, { observable, observer }));
35 | }
36 | if (observer) {
37 | out.push(() => observable.remove(observer));
38 | }
39 | return out;
40 | }, []);
41 | return () => observers.forEach(fn => fn());
42 | }
43 |
--------------------------------------------------------------------------------
/src/observable/template.pug:
--------------------------------------------------------------------------------
1 | Scene
2 | Box(:position="[0, 0, 5]")
3 |
--------------------------------------------------------------------------------
/src/observable/vue.pug:
--------------------------------------------------------------------------------
1 | extends ~begin-build/component/template
2 |
3 | block styles
4 | block scripts
5 |
--------------------------------------------------------------------------------
/src/physics/abstract.js:
--------------------------------------------------------------------------------
1 | import { PhysicsImpostor, Vector3 } from '@babylonjs/core';
2 | import AbstractEntity from '../entity/abstract';
3 | import { capitalize } from '../util';
4 |
5 | const TYPES = {
6 | BOX: 'box',
7 | CYLINDER: 'cylinder',
8 | HEIGHTMAP: 'heightmap',
9 | MESH: 'mesh',
10 | PARTICLE: 'particle',
11 | PLANE: 'plane',
12 | SPHERE: 'sphere',
13 | };
14 |
15 | export default {
16 | mixins: [AbstractEntity],
17 |
18 | inject: {
19 | gravity: {
20 | from: 'SceneGravity',
21 | default: new Vector3(0, -9.81, 0),
22 | },
23 | },
24 |
25 | props: {
26 | type: {
27 | validator: value => Object.values(TYPES).includes(value),
28 | default: Object.values(TYPES)[0],
29 | },
30 |
31 | mass: {
32 | type: Number,
33 | default: 0,
34 | },
35 |
36 | friction: {
37 | type: Number,
38 | default: 0.2,
39 | },
40 |
41 | restitution: {
42 | type: Number,
43 | default: 0.2,
44 | },
45 |
46 | options: {
47 | type: Object,
48 | default: undefined,
49 | },
50 |
51 | ignoreParent: {
52 | type: Boolean,
53 | default: false,
54 | },
55 |
56 | bidirectional: {
57 | type: Boolean,
58 | default: true,
59 | },
60 | },
61 |
62 | computed: {
63 | impostor() {
64 | return PhysicsImpostor[`${capitalize(this.type)}Impostor`];
65 | },
66 | },
67 |
68 | methods: {
69 | create() {
70 | let options = {
71 | mass: this.mass,
72 | restitution: this.restitution,
73 | friction: this.friction,
74 | };
75 | if (this.options) {
76 | options.nativeOptions = this.options;
77 | }
78 | if (this.ignoreParent) {
79 | options.ignoreParent = true;
80 | }
81 | if (!this.bidirectional) {
82 | options.disableBidirectionalTransformation = true;
83 | }
84 | this.$replace(new PhysicsImpostor(this._$_parent, this.impostor, options, this.$scene));
85 | },
86 |
87 | },
88 |
89 | watch: {
90 | type() {
91 | this.create();
92 | },
93 |
94 | mass() {
95 | this.$entity.setMass(this.mass);
96 | },
97 |
98 | friction() {
99 | this.$entity.setParam('friction', this.friction);
100 | },
101 |
102 | restitution() {
103 | this.$entity.setParam('restitution', this.restitution);
104 | },
105 |
106 | options: {
107 | handler() {
108 | this.$entity.setParam('nativeOptions', this.options);
109 | },
110 | deep: true,
111 | },
112 |
113 | ignoreParent() {
114 | this.$entity.setParam('ignoreParent', this.ignoreParent);
115 | },
116 |
117 | disableBidirectionalTransformation() {
118 | this.$entity.setParam('disableBidirectionalTransformation', !this.bidirectional);
119 | },
120 | },
121 |
122 | onScene({ scene }) {
123 | if (!scene.getPhysicsEngine()) {
124 | scene.enablePhysics(this.gravity, this.getPhysicsPlugin());
125 | }
126 | },
127 |
128 | onParent() {
129 | this.create();
130 | },
131 | };
132 |
--------------------------------------------------------------------------------
/src/physics/cannon.js:
--------------------------------------------------------------------------------
1 | import cannon from 'cannon';
2 | import { CannonJSPlugin as Plugin } from '@babylonjs/core';
3 | import AbstractPhysics from './abstract';
4 |
5 | export default {
6 | mixins: [AbstractPhysics],
7 |
8 | methods: {
9 | getPhysicsPlugin() {
10 | return new Plugin(undefined, undefined, cannon);
11 | },
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/src/physics/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Add physics to an Entity component
4 |
5 | #### Details
6 |
7 | The BabylonJS [guide to using a physics engine](https://doc.babylonjs.com/how_to/using_the_physics_engine) can be helpful here.
8 |
9 | - Must be a child of the entity you wish to add physics to
10 | - The physics engine will be initilized automatically when a Physics component is used in the scene
11 | - By default uses Cannon.js as the physics engine and can be changed to Oimo.js on the Scene component with the `physics` attribute
12 | - Props (attributes) are reactive and can be changed dynamically
13 |
14 | #### Usage
15 |
16 | ```html
17 |
18 |
19 |
20 |
21 |
22 | ```
23 |
24 | #### Props
25 |
26 | - `type` (String) - The kind of physics impostor, see below for valid values:
27 | - `"box"`
28 | - `"cylinder"`
29 | - `"heightmap"`
30 | - `"mesh"`
31 | - `"particle"`
32 | - `"plane"`
33 | - `"sphere"`
34 | - `mass` (Number) - The object's mass in kg
35 | - `friction` (Number) - The impostor's friction when colliding against other impostors
36 | - `restitution` (Number) - The amount of force the body will "give back" when colliding
37 | - `options` (Object) - `nativeOptions` in BabylonJS (options passed to the underlying physics engine)
38 | - `ignoreParent` (Boolean) - To avoid using the compound system, set this flag to true (default false)
39 | - `bidirectional` (Boolean) - whether to consider changes made to the mesh's position and rotation (default true)
40 |
--------------------------------------------------------------------------------
/src/physics/index.js:
--------------------------------------------------------------------------------
1 | import Cannon from './cannon';
2 | import Oimo from './oimo';
3 |
4 | export {
5 | Cannon,
6 | Oimo,
7 | };
8 |
--------------------------------------------------------------------------------
/src/physics/oimo.js:
--------------------------------------------------------------------------------
1 | import * as oimo from 'oimo';
2 | import { OimoJSPlugin as Plugin } from '@babylonjs/core';
3 | import AbstractPhysics from './abstract';
4 |
5 | export default {
6 | mixins: [AbstractPhysics],
7 |
8 | methods: {
9 | getPhysicsPlugin() {
10 | return new Plugin(undefined, oimo);
11 | },
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/src/property/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Change a value in an Entity's underlying BabylonJS object
4 |
5 | #### Details
6 |
7 | - This system was developed to allow for manipulation to properties outside the scope of this Plugin
8 | - This plugin will not specify every possible property for every class in BabylonJS, use this Property system or obtain a reference to the underlying BabylonJS object in your Vue component script and consult the BabylonJS API documentation
9 | - These values are reactive, but check the BabylonJS class for the object you are manipulating to be sure this will actually change in the Scene
10 | - Use only one of the `any`, `float`, `color`, `vector`, or `matrix` props (attributes)
11 |
12 | #### Usage
13 |
14 | ```html
15 |
16 |
17 |
18 | ```
19 |
20 | #### Props
21 |
22 | - `name` (String) - the name of the property to set
23 | - `any` (any) - a value of any type to set
24 | - `float` (Number) - a number value to set
25 | - `color` (Color) - a Color from a helper or BabylonJS to set
26 | - `vector` (Vector) - a Vector from a helper or BabylonJS to set
27 | - `matrix` (Matrix) - a Matrix from a helper or BabylonJS to set
28 |
--------------------------------------------------------------------------------
/src/property/index.js:
--------------------------------------------------------------------------------
1 | import AbstractEntity from '../entity/abstract';
2 | import { isFloat } from '../util';
3 | import { vecValidator, toVec2, vec3, toVec3, vec4, toVec4 } from '../types/vector';
4 | import { color3, toColor3, color4, toColor4 } from '../types/color';
5 | import { matrix, toMatrix } from '../types/matrix';
6 |
7 | export default {
8 | mixins: [AbstractEntity],
9 |
10 | props: {
11 | name: {
12 | type: String,
13 | },
14 |
15 | any: {
16 | default: null,
17 | },
18 |
19 | float: {
20 | validator: isFloat,
21 | default: null,
22 | },
23 |
24 | color: {
25 | validator: value => color3.validator(value) || color4.validator(value),
26 | default: null,
27 | },
28 |
29 | vector: {
30 | validator: vecValidator,
31 | default: null,
32 | },
33 |
34 | matrix: {
35 | validator: matrix.validator,
36 | default: null,
37 | },
38 | },
39 |
40 | computed: {
41 | value() {
42 | if (this.any) {
43 | return this.any;
44 | }
45 | if (this.float !== null) {
46 | return this.float;
47 | }
48 | if (this.color) {
49 | if (color4.validator(this.color)) {
50 | return toColor4(this.color);
51 | }
52 | return toColor3(this.color);
53 | }
54 | if (this.vector) {
55 | if (vec4.validator(this.vector)) {
56 | return toVec4(this.vector);
57 | }
58 | if (vec3.validator(this.vector)) {
59 | return toVec3(this.vector);
60 | }
61 | return toVec2(this.vector);
62 | }
63 | if (this.matrix) {
64 | return toMatrix(this.matrix);
65 | }
66 | return null;
67 | },
68 | },
69 |
70 | methods: {
71 | set() {
72 | if (this._$_parent) {
73 | this._$_parent[this.name] = this.value;
74 | } else {
75 | this.$scene[this.name] = this.value;
76 | }
77 | },
78 | },
79 |
80 | watch: {
81 | value() {
82 | this.set();
83 | },
84 | },
85 |
86 | onParent() {
87 | this.set();
88 | },
89 | };
90 |
--------------------------------------------------------------------------------
/src/scene/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | This is the entry point for the entire 3D scene. All components of this library require this to be an ancestor.
4 |
5 | #### Details
6 |
7 | - Automatically creates the HTML Canvas object to be used by BabylonJS
8 | - If there are no cameras defined in the scene then the BabylonJS default environment will be created
9 | - Although physics options are defined on the scene, it will not be initialized until a `Physics` component is used
10 | - The model from this component is the raw BabylonJS scene object. Use this to obtain access to the engine and physics engine (when initialized).
11 |
12 | See [the BabylonJS api documentation on the Scene class](https://doc.babylonjs.com/api/classes/babylon.scene) for more details.
13 |
14 | #### Usage
15 |
16 | ```html
17 |
18 |
19 |
20 | ```
21 |
22 | By default the canvas will use all available space from the parent element. Use the following CSS to fill the entire page with the canvas object:
23 |
24 | ```css
25 | html, body {
26 | margin: 0;
27 | padding: 0;
28 | height: 100%;
29 | }
30 | ```
31 |
32 | #### Events
33 | - `engine` - When the scene object is available
34 | - `scene` - When the scene object is available
35 | - `complete` - When all child entities are available
36 | - All observables from `Scene`, see the Observable documentation for details
37 |
38 | #### Props
39 |
40 | - `ambient` (Color) - Ambient lighting color for the scene
41 | - `fog` (String) - The type of fog to use, see below for valid values:
42 | - `"none"`
43 | - `"exp"`
44 | - `"exp2"`
45 | - `"linear"`
46 | - `fogStart` (Number) - Starting distance for fog
47 | - `fogEnd` (Number) - Ending distance for fog
48 | - `fogDensity` (Number) - Density of fog for in `"exp"` or `"exp2"` modes
49 | - `fogColor` (Color) - Color to use for fog
50 | - `fullscreen` (Boolean) - Enable fullscreen - default `false`
51 | - `debug` (Boolean) - Enable debug mode - default `false`
52 | - `environment` (IEnvironmentHelperOptions) - Options for the default environment: [See the interface documentation](https://doc.babylonjs.com/api/interfaces/babylon.ienvironmenthelperoptions)
53 | - `main` (Color) - Primary color of all the available elements when using the default environment
54 | - `physics` (String) - Optionally change the physics engine to use, see below for valid values:
55 | - `"cannon"`
56 | - `"oimo"`
57 | - `gravity` (Vector3) - Set the direction of gravity when using the physics engine
58 |
--------------------------------------------------------------------------------
/src/scene/index.js:
--------------------------------------------------------------------------------
1 | import { Engine, Scene, Color3, Vector3 } from '@babylonjs/core';
2 | import { createBus, defer } from '../util';
3 | import { vecValidator as validator, toVec3 } from '../types/vector';
4 | import { color3, toColor3 } from '../types/color';
5 | import { registerObservers } from '../observable';
6 |
7 | const FOG_TYPES = {
8 | NONE: 'none',
9 | EXP: 'exp',
10 | EXP2: 'exp2',
11 | LINEAR: 'linear',
12 | };
13 |
14 | export default {
15 | provide() {
16 | return {
17 | EngineReady: this.EngineReady,
18 | SceneReady: this.SceneReady,
19 | SceneBus: this.sceneBus,
20 | SceneGravity: this.gravityVector3,
21 | EntityBus: this.$event,
22 | };
23 | },
24 |
25 | model: {
26 | prop: 'model',
27 | event: 'change',
28 | },
29 |
30 | props: {
31 | model: {
32 | type: Object,
33 | default: null,
34 | },
35 |
36 | ambient: {
37 | validator: color3.validator,
38 | default: () => Color3.Black(),
39 | },
40 |
41 | fog: {
42 | validator: value => Object.values(FOG_TYPES).includes(value),
43 | default: Object.values(FOG_TYPES)[0],
44 | },
45 |
46 | fogStart: {
47 | type: Number,
48 | default: 20,
49 | },
50 |
51 | fogEnd: {
52 | type: Number,
53 | default: 60,
54 | },
55 |
56 | fogDensity: {
57 | type: Number,
58 | default: 0.1,
59 | },
60 |
61 | fogColor: {
62 | validator: color3.validator,
63 | default: () => new Color3(0.2, 0.2, 0.3),
64 | },
65 |
66 | fullscreen: {
67 | type: Boolean,
68 | default: false,
69 | },
70 |
71 | debug: {
72 | type: Boolean,
73 | default: false,
74 | },
75 |
76 | environment: {
77 | type: Object,
78 | default: undefined,
79 | },
80 |
81 | main: {
82 | validator: color3.validator,
83 | default: null,
84 | },
85 |
86 | gravity: {
87 | validator,
88 | default: () => new Vector3(0, -9.81, 0),
89 | },
90 | },
91 |
92 | computed: {
93 | ambientColor() {
94 | return toColor3(this.ambient);
95 | },
96 |
97 | fogMode() {
98 | return Scene[`FOGMODE_${this.fog.toUpperCase()}`];
99 | },
100 |
101 | fogColor3() {
102 | return toColor3(this.fogColor);
103 | },
104 |
105 | mainColor() {
106 | if (!this.main) {
107 | return null;
108 | }
109 | return toColor3(this.main);
110 | },
111 |
112 | gravityVecor3() {
113 | return toVec3(this.gravity);
114 | },
115 | },
116 |
117 | methods: {
118 | setAmbientColor() {
119 | this.scene.ambientColor = this.ambientColor;
120 | },
121 |
122 | setFogStart() {
123 | this.scene.fogStart = this.fogStart;
124 | },
125 |
126 | setFogEnd() {
127 | this.scene.fogStart = this.fogEnd;
128 | },
129 |
130 | setFogDensity() {
131 | this.scene.fogDensity = this.fogDensity;
132 | },
133 |
134 | setFogColor() {
135 | this.scene.fogColor = this.fogColor3;
136 | },
137 |
138 | setFogMode() {
139 | this.scene.fogMode = this.fogMode;
140 | switch (this.fog) {
141 | case 'none':
142 | break;
143 | case 'linear':
144 | this.setFogStart();
145 | this.setFogEnd();
146 | break;
147 | default:
148 | this.setFogDensity();
149 | }
150 | this.setFogColor();
151 | },
152 |
153 | requestFullScreen() {
154 | if (this.fullscreen) {
155 | this.$refs.scene.requestFullScreen();
156 | }
157 | },
158 |
159 | debugLayer() {
160 | if (this.debug) {
161 | this.scene.debugLayer.show();
162 | } else {
163 | this.scene.debugLayer.hide();
164 | }
165 | },
166 |
167 | resize() {
168 | this.engine.resize();
169 | },
170 |
171 | defaultEnvironment() {
172 | if (this.scene.cameras.length < 1) {
173 | this.scene.createDefaultCameraOrLight(true, true, true);
174 | let helper = this.scene.createDefaultEnvironment(this.environment);
175 | if (this.mainColor) {
176 | helper.setMainColor(this.mainColor);
177 | }
178 | }
179 | },
180 |
181 | setScene() {
182 | this.engine = new Engine(this.$refs.scene, true);
183 | this.$emit('engine', this.engine);
184 | this.scene = new Scene(this.engine);
185 | this.$emit('scene', this.scene);
186 | this.observers = registerObservers.call(this, this.scene);
187 | this.setAmbientColor();
188 | this.setFogMode();
189 | this.resolveScene(this.scene);
190 | this.resolveEngine(this.engine);
191 | this.engine.runRenderLoop(() => this.scene.render());
192 | this.requestFullScreen();
193 | this.debugLayer();
194 | this.scene.executeWhenReady(this.resize); // HACK: investigate sqaush effect on initial load
195 | },
196 |
197 | setGravity() {
198 | if (this.scene && this.scene.getPhysicsEngine()) {
199 | this.physicsEngine.setGravity(this.gravityVector3);
200 | }
201 | },
202 |
203 | register({ name }) {
204 | this._$_children[name] = defer();
205 | },
206 |
207 | complete({ name, entity }) {
208 | this._$_children[name].complete({ name, entity });
209 | },
210 | },
211 |
212 | watch: {
213 | ambientColor() {
214 | this.setAmbientColor();
215 | },
216 |
217 | fog() {
218 | this.setFogMode();
219 | },
220 |
221 | fogDensity() {
222 | this.setFogDensity();
223 | },
224 |
225 | fogStart() {
226 | this.setFogStart();
227 | },
228 |
229 | fogEnd() {
230 | this.setFogEnd();
231 | },
232 |
233 | fogColor3() {
234 | this.setFogColor();
235 | },
236 |
237 | fullscreen() {
238 | this.requestFullScreen();
239 | },
240 |
241 | debug() {
242 | this.debugLayer();
243 | },
244 |
245 | gravityVector3() {
246 | this.setGravity();
247 | },
248 | },
249 |
250 | beforeCreate() {
251 | this.sceneBus = createBus.call(this);
252 | this.SceneReady = new Promise(resolve => {
253 | this.resolveScene = resolve;
254 | });
255 | this.EngineReady = new Promise(resolve => {
256 | this.resolveEngine = resolve;
257 | });
258 | this.$event = createBus.call(this);
259 | },
260 |
261 | beforeMount() {
262 | this._$_children = {};
263 | this.$event.$on('register', this.register);
264 | this.$event.$on('complete', this.complete);
265 | },
266 |
267 | async mounted() {
268 | this.setScene(this.$refs.scene);
269 | window.addEventListener('resize', this.resize);
270 | let children = await Promise.all(Object.values(this._$_children));
271 | children = children.reduce((out, { name, entity }) => {
272 | out[name] = entity;
273 | return out;
274 | }, {});
275 | this.$emit('complete', { children, scene: this.scene, engine: this.engine });
276 | this.defaultEnvironment();
277 | },
278 |
279 | beforeDestroy() {
280 | window.removeEventListener('resize', this.resize);
281 | this.engine.stopRenderLoop();
282 | this.observers();
283 | this.scene.dispose();
284 | this.vrHelper = null;
285 | this.scene = null;
286 | this.engine = null;
287 | },
288 |
289 | render(createElement) {
290 | return createElement('canvas', {
291 | ref: 'scene',
292 | style: { height: '100%', width: '100%' },
293 | }, this.$slots.default);
294 | },
295 | };
296 |
--------------------------------------------------------------------------------
/src/shader/attribute.js:
--------------------------------------------------------------------------------
1 | import Variable from './variable';
2 |
3 | export default {
4 | mixins: [Variable],
5 |
6 | beforeCreate() {
7 | this.kind = 'attribute';
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/src/shader/content.js:
--------------------------------------------------------------------------------
1 | import AbstractEntity from '../entity/abstract';
2 |
3 | export default {
4 | mixins: [AbstractEntity],
5 |
6 | inject: {
7 | ShaderName: {
8 | default: null,
9 | },
10 | },
11 |
12 | data() {
13 | return {
14 | text: null,
15 | };
16 | },
17 |
18 | props: {
19 | name: {
20 | type: String,
21 | validator() {
22 | return value => value || this.ShaderName;
23 | },
24 | },
25 |
26 | content: {
27 | type: String,
28 | default: null,
29 | },
30 | },
31 |
32 | computed: {
33 | uid() {
34 | return this.name || this.ShaderName;
35 | },
36 |
37 | value() {
38 | return this.content || this.text;
39 | },
40 |
41 | shader() {
42 | return {
43 | name: this.uid,
44 | value: this.value,
45 | };
46 | },
47 | },
48 |
49 | watch: {
50 | shader() {
51 | this.setStore();
52 | },
53 | },
54 |
55 | mounted() {
56 | this.text = this.$refs.content.textContent;
57 | this.setStore();
58 | },
59 |
60 | render(createElement) {
61 | return createElement('div', {
62 | ref: 'content',
63 | }, this.$slots.default);
64 | },
65 | };
66 |
--------------------------------------------------------------------------------
/src/shader/docs.md:
--------------------------------------------------------------------------------
1 | #### Details
2 |
3 | - This must be a child of a Mesh component
4 | - It is important to use a unique name value when using this component to leverage shader caching inside of the BabylonJS `ShadersStore`
5 | - Not using the `name` attribute when recommended may lead to memory leaks!
6 | - There are several ways to define your vertex and fragment code try to follow the recommendations for each use-case
7 | - Pick one method of each loading vertex and fragment code
8 | - You can mix-and-match methods of loading
9 | - Create reusable components with Vue to share your shader materials with several different meshes
10 |
11 | #### Usage
12 |
13 | ```html
14 |
15 |
16 |
17 |
18 |
19 | ```
20 |
21 | #### Props
22 |
23 | - `name` (String) - A unique id value to assign to this shader
24 | - `vertex` (String) - vertex name in shader store (recommended for independently resuable shader files) using this and `fragment` together this does not require a `name` attribute
25 | - `vertexElement` (String) - vertex script id (Not recommended, use the Vertex component)
26 | - `vertexShader` (String) - raw vertex shader code (USE THE `name` prop for safe caching!)
27 | - `fragment` (String) - fragment name in shader store (recommended for independently resuable shader files) using this and `vertex` together does not require a `name` attribute
28 | - `fragmentElement` (String) - fragment script id (Not recommended, use the Fragment component)
29 | - `fragmentShader` (String) - raw fragment shader code (USE THE `name` prop for safe caching!)
30 | - `shader` (String) - shader and fragment name in shader store (recommended for resuable shader files) using this does not require a `name` attribute
31 | - `src` (String) - path to an fx file on your server (Only recommended when using the webpack file plugin, using a CDN, or in specific environments)
32 |
33 | ### Shader Content
34 |
35 | Use a separate component to define your shader code
36 |
37 | #### Components
38 |
39 | - Vertex
40 | - Fragment
41 |
42 | #### Details
43 |
44 | - Must be a child of a Shader component
45 | - When using only separate Vertex and/or Fragment components it is not necessary to provide a name to the parent Shader, but is necessary to provide to this component
46 | - If the parent has a name then it is not necessary to provide a name to this component, both Vertex and Fragment components will inherit the name
47 | - Names can be shared if the Fragment and Vertex components are children of the same Shader component, but in this case you should probably provide the name to the Shader component instead
48 | - When writing in the Pug langage, it is possible to provide body text of these components by using the dot (`.`) operator as the parent element
49 | - Body content is not reactive at the moment since Vue does not watch these changes by default
50 | - It is only recommended to use body content shader code in the prototyping phase
51 |
52 | #### Usage
53 |
54 | ```html
55 |
56 |
57 |
58 |
59 |
60 | // Body content fragment code here
61 |
62 |
63 |
64 |
65 | ```
66 |
67 | #### Props
68 |
69 | - `name` (String) - A unique id value to assign to this shader
70 | - `content` (String) - The text content of the code instead of the body content of this element
71 |
72 | #### Shader Variables
73 |
74 | Set a vairable for your shader code
75 |
76 | #### Components
77 |
78 | - Uniform
79 | - Attribute
80 |
81 | #### Details
82 |
83 | - Must be a child of a Shader component
84 | - Specific variable value types are converted automatically
85 | - Use only one appropriate attribute to define the type of your variable
86 | - Always use the `variable` attribute to define what your variable is named in your shader code
87 | - Variables are reactive and will update the Shader automatically when changed
88 |
89 | #### Usage
90 |
91 | ```html
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | ```
108 |
109 | #### Props
110 |
111 | - `variable` (String) - [required] the name of the variable in GLSL code
112 | - `float` (Number) - a Float value to pass into the shader
113 | - `color` (Color3|Color4) - a Color value to pass into the shader
114 | - `vector` (Vector2|Vector3|Vector4) - a Vector value to pass into the shader
115 | - `matrix` (Matrix) - a Matrix value to pass into the shader
116 | - `matrix2x2` (Matrix) - a 2D Matrix value to pass into the shader
117 | - `matrix3x3` (Matrix) - a 3D Matrix value to pass into the shader
118 | - `array` (Array) - an Array value to pass into the shader
119 |
--------------------------------------------------------------------------------
/src/shader/fragment.js:
--------------------------------------------------------------------------------
1 | import Content from './content';
2 |
3 | export default {
4 | mixins: [Content],
5 |
6 | methods: {
7 | setStore() {
8 | this.$bus.$emit('setFragment', this.shader);
9 | },
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/src/shader/index.js:
--------------------------------------------------------------------------------
1 | import { Effect, ShaderMaterial } from '@babylonjs/core';
2 | import AbstractEntity from '../entity/abstract';
3 | import { id } from '../util';
4 |
5 | const VERTEX = 'VertexShader';
6 | const FRAGMENT = 'FragmentShader';
7 | const ATTRIBUTES = {
8 | POSITION: 'position',
9 | NORMAL: 'normal',
10 | UV: 'uv',
11 | };
12 | const UNIFORMS = {
13 | WORLD: 'world',
14 | WORLD_VIEW: 'worldView',
15 | WORLD_VIEW_PROJECTION: 'worldViewProjection',
16 | VIEW: 'view',
17 | PROJECTION: 'projection',
18 | TIME: 'time',
19 | };
20 | const NAME = 'vue-babylonjs';
21 | const DEFAULT_VERTEX_NAME = `${NAME}${VERTEX}`;
22 | const DEFAULT_VERTEX = `
23 | attribute vec3 position;
24 | attribute vec2 uv;
25 | uniform mat4 worldViewProjection;
26 | uniform float time;
27 | varying vec2 vUv;
28 |
29 | void main() {
30 | gl_Position = worldViewProjection * vec4(position, 1.0);
31 | vUv = uv;
32 | }
33 | `;
34 | const DEFAULT_FRAGMENT_NAME = `${NAME}${FRAGMENT}`;
35 | const DEFAULT_FRAGMENT = `
36 | precision highp float;
37 |
38 | void main() {
39 | gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
40 | }
41 | `;
42 |
43 | export default {
44 | mixins: [AbstractEntity],
45 |
46 | data() {
47 | return {
48 | uniformStore: {},
49 | attributeStore: {},
50 | vertexComponent: null,
51 | fragmentComponent: null,
52 | };
53 | },
54 |
55 | provide() {
56 | return {
57 | ShaderName: this.name,
58 | };
59 | },
60 |
61 | props: {
62 | name: {
63 | type: String,
64 | default: null,
65 | },
66 |
67 | vertex: { // vertex name in shader store
68 | type: String,
69 | default: null,
70 | },
71 |
72 | vertexElement: { // vertex script id
73 | type: String,
74 | default: null,
75 | },
76 |
77 | vertexShader: { // raw vertex shader code
78 | type: String,
79 | default: null,
80 | },
81 |
82 | fragment: { // fragment name in shader store
83 | type: String,
84 | default: null,
85 | },
86 |
87 | fragmentElement: { // fragment script id
88 | type: String,
89 | default: null,
90 | },
91 |
92 | fragmentShader: { // raw fragment shader code
93 | type: String,
94 | default: null,
95 | },
96 |
97 | shader: { // shader and fragment name in shader store
98 | type: String,
99 | default: null,
100 | },
101 |
102 | src: { // fx file path
103 | type: String,
104 | default: null,
105 | },
106 | },
107 |
108 | computed: {
109 | options() {
110 | if (this.src) {
111 | return this.src;
112 | }
113 | if (this.shader) {
114 | return {
115 | fragment: this.shader,
116 | vertex: this.shader,
117 | };
118 | }
119 | let options = {};
120 | if (this.vertexComponent) {
121 | options.vertex = this.vertexComponent;
122 | } else if (this.vertex) {
123 | options.vertex = this.vertex;
124 | } else if (this.vertexElement) {
125 | options.vertexElement = this.vertexElement;
126 | } else if (this.vertexShader) {
127 | this.storeShader(VERTEX, this.uid, this.vertexShader);
128 | options.vertex = this.uid;
129 | } else {
130 | if (!Effect.ShadersStore[DEFAULT_VERTEX_NAME]) {
131 | Effect.ShadersStore[DEFAULT_VERTEX_NAME] = DEFAULT_VERTEX;
132 | }
133 | options.vertex = NAME;
134 | }
135 | if (this.fragmentComponent) {
136 | options.fragment = this.fragmentComponent;
137 | } else if (this.fragment) {
138 | options.fragment = this.fragment;
139 | } else if (this.fragmentElement) {
140 | options.fragmentElement = this.fragmentElement;
141 | } else if (this.fragmentShader) {
142 | this.storeShader(FRAGMENT, this.uid, this.fragmentShader);
143 | options.fragment = this.uid;
144 | } else {
145 | if (!Effect.ShadersStore[DEFAULT_FRAGMENT_NAME]) {
146 | Effect.ShadersStore[DEFAULT_FRAGMENT_NAME] = DEFAULT_FRAGMENT;
147 | }
148 | options.fragment = NAME;
149 | }
150 | return options;
151 | },
152 |
153 | attributes() {
154 | return Object.values(ATTRIBUTES).concat(Object.keys(this.attributeStore));
155 | },
156 |
157 | uniforms() {
158 | return Object.values(UNIFORMS).concat(Object.keys(this.uniformStore));
159 | },
160 |
161 | variables() {
162 | return {
163 | attributes: this.attributes,
164 | uniforms: this.uniforms,
165 | };
166 | },
167 | },
168 |
169 | methods: {
170 | createMaterial() {
171 | if (!this._$_parent) {
172 | return;
173 | }
174 | this.$replace(new ShaderMaterial(this.name, this.$scene, this.options, this.variables));
175 | this._$_parent.material = this.$entity;
176 | },
177 |
178 | setValue(store, variable, value) {
179 | this.$entity[`set${store[variable]}`](variable, value);
180 | },
181 |
182 | storeShader(type, name, value) {
183 | Effect.ShadersStore[name + type] = value;
184 | },
185 |
186 | getStore(kind) {
187 | if (kind === 'attribute') {
188 | return this.attributeStore;
189 | }
190 | return this.uniformStore;
191 | },
192 | },
193 |
194 | watch: {
195 | options() {
196 | this.createMaterial();
197 | },
198 | },
199 |
200 | events: {
201 | registerVariable({ kind, variable, type }) {
202 | this.getStore(kind)[variable] = type;
203 | },
204 |
205 | setVariable({ kind, variable, value }) {
206 | this.setValue(this.getStore(kind), variable, value);
207 | },
208 |
209 | disposeVariable({ kind, variable }) {
210 | delete this.getStore(kind)[variable];
211 | },
212 |
213 | setVertex({ name, value }) {
214 | this.vertexComponent = name;
215 | this.storeShader(VERTEX, name, value);
216 | },
217 |
218 | setFragment({ name, value }) {
219 | this.fragmentComponent = name;
220 | this.storeShader(FRAGMENT, name, value);
221 | },
222 | },
223 |
224 | beforeCreate() {
225 | this.uid = id();
226 | },
227 |
228 | onParent() {
229 | this.createMaterial();
230 | },
231 |
232 | beforeRender() {
233 | this.$entity.setFloat('time', performance.now());
234 | },
235 |
236 | beforeDestroy() {
237 | this._$_destroyed = true;
238 | this.$entity.dispose();
239 | },
240 | };
241 |
--------------------------------------------------------------------------------
/src/shader/uniform.js:
--------------------------------------------------------------------------------
1 | import Variable from './variable';
2 |
3 | export default {
4 | mixins: [Variable],
5 |
6 | beforeCreate() {
7 | this.kind = 'uniform';
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/src/shader/variable.js:
--------------------------------------------------------------------------------
1 | import AbstractEntity from '../entity/abstract';
2 | import { isFloat, isFloatArray } from '../util';
3 | import { vecValidator, toVec2, vec3, toVec3, vec4, toVec4 } from '../types/vector';
4 | import { color3, toColor3, color4, toColor4 } from '../types/color';
5 | import { matrix, toMatrix } from '../types/matrix';
6 |
7 | export default {
8 | mixins: [AbstractEntity],
9 |
10 | props: {
11 | variable: {
12 | type: String,
13 | },
14 |
15 | float: {
16 | validator: isFloat,
17 | default: null,
18 | },
19 |
20 | color: {
21 | validator: value => color3.validator(value) || color4.validator(value),
22 | default: null,
23 | },
24 |
25 | vector: {
26 | validator: vecValidator,
27 | default: null,
28 | },
29 |
30 | matrix: {
31 | validator: matrix.validator,
32 | default: null,
33 | },
34 |
35 | matrix2x2: {
36 | type: Float32Array,
37 | default: null,
38 | },
39 |
40 | matrix3x3: {
41 | type: Float32Array,
42 | default: null,
43 | },
44 |
45 | array: {
46 | validator: isFloatArray,
47 | default: null,
48 | },
49 | },
50 |
51 | computed: {
52 | details() {
53 | let type;
54 | let value;
55 | if (this.float !== null) {
56 | value = this.float;
57 | type = 'Float';
58 | if (isFloatArray(this.float)) {
59 | type = 'Floats';
60 | }
61 | } else if (this.color) {
62 | if (color4.validator(this.color)) {
63 | value = toColor4(this.color);
64 | type = 'Color4';
65 | } else {
66 | value = toColor3(this.color);
67 | type = 'Color3';
68 | }
69 | } else if (this.vector) {
70 | if (vec4.validator(this.vector)) {
71 | value = toVec4(this.vector);
72 | type = 'Vector4';
73 | } else if (vec3.validator(this.vector)) {
74 | value = toVec3(this.vector);
75 | type = 'Vector3';
76 | } else {
77 | value = toVec2(this.vector);
78 | type = 'Vector2';
79 | }
80 | } else if (this.matrix) {
81 | value = toMatrix(this.matrix);
82 | type = 'Matrix';
83 | } else if (this.matrix2x2) {
84 | value = this.matrix2x2;
85 | type = 'Matrix2x2';
86 | } else if (this.matrix3x3) {
87 | value = this.matrix3x3;
88 | type = 'Matrix3x3';
89 | } else if (this.array) {
90 | value = this.array;
91 | type = 'Array2';
92 | if (value.length > 2) {
93 | type = 'Array3';
94 | }
95 | }
96 | return {
97 | kind: this.kind,
98 | variable: this.variable,
99 | type,
100 | value,
101 | };
102 | },
103 | },
104 |
105 | methods: {
106 | register() {
107 | this.$bus.$emit('registerVariable', this.details);
108 | },
109 | set() {
110 | this.$bus.$emit('setVariable', this.details);
111 | },
112 | dispose() {
113 | this.$bus.$emit('disposeVariable', this.details);
114 | },
115 | },
116 |
117 | watch: {
118 | details() {
119 | this.set();
120 | },
121 | },
122 |
123 | onScene() {
124 | return this.details;
125 | },
126 |
127 | onParent() {
128 | this.register();
129 | this.set();
130 | },
131 |
132 | beforeDistroy() {
133 | this.dispose();
134 | },
135 | };
136 |
--------------------------------------------------------------------------------
/src/shader/vertex.js:
--------------------------------------------------------------------------------
1 | import Content from './content';
2 |
3 | export default {
4 | mixins: [Content],
5 |
6 | methods: {
7 | setStore() {
8 | this.$bus.$emit('setVertex', this.shader);
9 | },
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/src/texture/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | A texture to use on a Material component
4 |
5 | #### Details
6 |
7 | - Must be a child of the Material component
8 | - Properties of this component are reactive and will automatically update the parent Material
9 |
10 | #### Usage
11 |
12 | ```html
13 |
14 |
15 |
16 |
17 |
18 | ```
19 |
20 | #### Props
21 |
22 | - `type` (String) - type name with "Texture" automatically added, see below for valid values:
23 | - `"diffuse"` when in PBRMaterial mode, automatically renamed to `albedoTexture`
24 | - `"ambient"`
25 | - `"opacity"`
26 | - `"reflection"`
27 | - `"emissive"`
28 | - `"specular"`
29 | - `"bump"`
30 | - `"lightmap"`
31 | - `"refraction"`
32 | - `"cameraColorGrading"`
33 | - `"albedo"` (PBRMaterial)
34 | - `"reflectivity"` (PBRMaterial)
35 | - `"metallic"` (PBRMaterial)
36 | - `"microSurface"` (PBRMaterial)
37 | - `"environmentBRDF"` (PBRMaterial)
38 | - `"metallicRoughness"` (PBRMaterial) automatically renamed to `metallicTexture`
39 | - `"environment"` (PBRMaterial) automatically renamed to `reflectionTexture`
40 | - `"normal"` (PBRMaterial) automatically renamed to `bumpTexture`
41 | - `"occlusion"` (PBRMaterial) automatically renamed to `ambientTexture`
42 | - `"specularGlossiness"` (PBRMaterial) automatically renamed to `reflectivityTexture`
43 | - `property` (String) - when not using the `type` prop, the name of the texture property to set on the Material
44 | - `src` (String) - the uri location of the image src for this texture
45 | - `value` (Texture) - when not using the `src` prop use a BabylonJS texture object
46 |
--------------------------------------------------------------------------------
/src/texture/index.js:
--------------------------------------------------------------------------------
1 | import { Texture } from '@babylonjs/core';
2 | import AbstractEntity from '../entity/abstract';
3 |
4 | const TYPES = {
5 | DIFFUSE: 'diffuse',
6 | AMBIENT: 'ambient',
7 | OPACITY: 'opacity',
8 | REFLECTION: 'reflection',
9 | EMISSIVE: 'emissive',
10 | SPECULAR: 'specular',
11 | BUMP: 'bump',
12 | LIGHTMAP: 'lightmap',
13 | REFRACTION: 'refraction',
14 | CAMERA_COLOR_GRADING: 'cameraColorGrading',
15 |
16 | // PBR textures
17 | ALBEDO: 'albedo',
18 | REFLECTIVITY: 'reflectivity',
19 | METALLIC: 'metallic',
20 | MICROSURFACE: 'microSurface',
21 | ENVIRONMENT_BRDF: 'environmentBRDF',
22 |
23 | // PBR renames
24 | METALLIC_ROUGHNESS: 'metallicRoughness',
25 | ENVIRONMENT: 'environment',
26 | NORMAL: 'normal',
27 | OCCLUSION: 'occlusion',
28 | SPECULAR_GLOSSINESS: 'specularGlossiness',
29 | };
30 |
31 | export default {
32 | mixins: [AbstractEntity],
33 |
34 | props: {
35 | type: {
36 | validator: value => Object.values(TYPES).includes(value),
37 | default: Object.values(TYPES)[0],
38 | },
39 |
40 | property: {
41 | type: String,
42 | default: null,
43 | },
44 |
45 | src: {
46 | type: String,
47 | default: null,
48 | },
49 |
50 | value: {
51 | validator: value => value instanceof Texture,
52 | default: null,
53 | },
54 | },
55 |
56 | computed: {
57 | identifier() {
58 | return this.property || `${this.type}Texture`;
59 | },
60 | },
61 |
62 | methods: {
63 | create() {
64 | let texture = this.value || new Texture(this.src, this.$scene);
65 | this.$replace(texture);
66 | },
67 |
68 | dispose(property = this.identifier) {
69 | this.$bus.$emit('disposeTexture', { property });
70 | },
71 |
72 | set() {
73 | this.$bus.$emit('setTexture', {
74 | property: this.identifier,
75 | texture: this.$entity,
76 | });
77 | },
78 |
79 | change() {
80 | if (!this.$entity) {
81 | this.create();
82 | }
83 | this.set();
84 | },
85 | },
86 |
87 | watch: {
88 | identifier(_, property) {
89 | this.dispose(property);
90 | this.set();
91 | },
92 |
93 | src() {
94 | this.dispose();
95 | this.create();
96 | this.set();
97 | },
98 |
99 | value() {
100 | this.dispose();
101 | this.create();
102 | this.set();
103 | },
104 | },
105 |
106 | onParent() {
107 | this.$bus.$on('change', this.change);
108 | this.change();
109 | },
110 |
111 | beforeDestroy() {
112 | this.dispose();
113 | },
114 | };
115 |
--------------------------------------------------------------------------------
/src/types/color.js:
--------------------------------------------------------------------------------
1 | import { Color3, Color4 } from '@babylonjs/core';
2 | import { isFloatArray, isBetween0and1 } from '../util';
3 |
4 | /* eslint-disable security/detect-unsafe-regex */
5 | export const isHexColor3 = value => /^#?([\da-f]{3}){1,2}$/i.test(value);
6 | export const isHexColor4 = value => /^#?([\da-f]{4}){1,2}$/i.test(value);
7 | /* eslint-enable */
8 |
9 | export const colorValidator = (value, type = Color3) => {
10 | if (value === null) {
11 | return false;
12 | }
13 | if (value instanceof type || (isFloatArray(value) && value.every(isBetween0and1))) {
14 | return true;
15 | }
16 | if (typeof value === 'string') {
17 | if (type === Color3) {
18 | return isHexColor3(value);
19 | }
20 | return isHexColor4(value);
21 | }
22 | if (!isBetween0and1(value.r) || !isBetween0and1(value.g) || !isBetween0and1(value.b)) {
23 | return false;
24 | }
25 | if (type === Color3) {
26 | return true;
27 | }
28 | return isBetween0and1(value.a);
29 | };
30 |
31 | export const toColor = (value, Type, transform) => {
32 | if (value instanceof Type) {
33 | return value;
34 | }
35 | if (Array.isArray(value)) {
36 | return Type.FromArray(value);
37 | }
38 | if (typeof value === 'string') {
39 | value = value.replace('#', '');
40 | if (value.length < 6) {
41 | value = [...value].reduce((o, a) => o.concat([a, a]), []).join('');
42 | }
43 | return Type.FromHexString(`#${value.toUpperCase()}`);
44 | }
45 | return new Type(...transform(value));
46 | };
47 |
48 | export const color3 = {
49 | validator: colorValidator,
50 | default: () => Color3.White(),
51 | };
52 |
53 | export const toColor3 = value => toColor(value, Color3, ({ r, g, b }) => [r, g, b]);
54 |
55 | export const color4 = {
56 | validator: value => colorValidator(value, Color4),
57 | default: () => Color3.White().toColor4(),
58 | };
59 |
60 | export const toColor4 = value => toColor(value, Color4, ({ r, g, b, a }) => [r, g, b, a]);
61 |
62 | export const $color = (...value) => {
63 | if (Array.isArray(value[0])) {
64 | [value] = value;
65 | }
66 | if (colorValidator(value, Color4)) {
67 | return toColor4(value);
68 | }
69 | return toColor3(value);
70 | };
71 |
--------------------------------------------------------------------------------
/src/types/docs.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | #### Vector
4 |
5 | Vectors can be any of the following:
6 |
7 | - An Array of 2, 3, or 4 Numbers between 0 and 1
8 | - A call to the `$vector` helper using Numbers between 0 and 1
9 | - An Object from the `Vector2`, `Vector3`, or `Vector4` classes in BabylonJS
10 |
11 | ##### Template:
12 |
13 | ```html
14 |
15 |
16 |
17 |
18 | ```
19 |
20 | ##### Script:
21 |
22 | ```js
23 | let { Vector3 } = require('vue-babylonjs/classes');
24 |
25 | module.exports = {
26 | data() {
27 | return {
28 | myArray: [1, 0, 1],
29 | myVector: new Vector3(0, 1, 0),
30 | };
31 | },
32 | };
33 | ```
34 |
35 | #### Color
36 |
37 | Colors can be any of the following:
38 |
39 | - An Array of 3 or 4 Numbers between 0 and 1
40 | - A call to the `$color` helper using Numbers between 0 and 1
41 | - An Object from the `Color3` or `Color4` classes in BabylonJS
42 | - A HTML color code String with an optional alpha channel (case insenisitive)
43 |
44 | ##### Template:
45 |
46 | ```html
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ```
60 |
61 | ##### Script:
62 |
63 | ```js
64 | let { Color3 } = require('vue-babylonjs/classes');
65 |
66 | module.exports = {
67 | data() {
68 | return {
69 | myArray: [1, 0, 1],
70 | myColor3: new Color3(0, 1, 0),
71 | };
72 | },
73 | };
74 | ```
75 |
76 | #### Matrix
77 |
78 | Matricies can be any of the following:
79 |
80 | - An Array of Numbers
81 | - A call to the `$matrix` helper with Numbers as arguments
82 | - An Object from the `Matrix` class in BabylonJS
83 |
84 | ##### Template:
85 |
86 | ```html
87 |
88 |
89 |
90 |
91 | ```
92 |
93 | ##### Script:
94 |
95 | ```js
96 | let { Matrix } = require('vue-babylonjs/classes');
97 |
98 | module.exports = {
99 | data() {
100 | return {
101 | myArray: [1, 2, 3, 4, 5, 6, 7, 8, 9],
102 | myMatrix: new Matrix(0, 1, 0),
103 | };
104 | },
105 | };
106 | ```
107 |
--------------------------------------------------------------------------------
/src/types/matrix.js:
--------------------------------------------------------------------------------
1 | import { Matrix } from '@babylonjs/core';
2 | import { isFloatArray } from '../util';
3 |
4 | export const toMatrix = value => {
5 | if (value instanceof Matrix) {
6 | return value;
7 | }
8 | return Matrix.FromArray(value);
9 | };
10 |
11 | export const matrix = {
12 | validator: value => value !== null && (isFloatArray(value) || value instanceof Matrix),
13 | default: () => Matrix.Zero(),
14 | };
15 |
16 | export const $matrix = (...value) => {
17 | if (Array.isArray(value[0])) {
18 | [value] = value;
19 | }
20 | return toMatrix(value);
21 | };
22 |
--------------------------------------------------------------------------------
/src/types/vector.js:
--------------------------------------------------------------------------------
1 | import { Vector2, Vector3, Vector4 } from '@babylonjs/core';
2 | import { isFloat, isFloatArray } from '../util';
3 |
4 | export const vecValidator = (value, type = Vector2) => {
5 | if (value === null) {
6 | return false;
7 | }
8 | if (value instanceof type || isFloatArray(value)) {
9 | return true;
10 | }
11 | if (!isFloat(value.x) || !isFloat(value.y)) {
12 | return false;
13 | }
14 | if (type === Vector2) {
15 | return true;
16 | }
17 | if (!isFloat(value.z)) {
18 | return false;
19 | }
20 | if (type === Vector3) {
21 | return true;
22 | }
23 | return isFloat(value.w);
24 | };
25 |
26 | export const toVec = (value, Type, transform) => {
27 | if (value instanceof Type) {
28 | return value;
29 | }
30 | if (Array.isArray(value)) {
31 | return Type.FromArray(value);
32 | }
33 | return new Type(...transform(value));
34 | };
35 |
36 | export const vec2 = {
37 | validator: vecValidator,
38 | default: () => Vector2.Zero(),
39 | };
40 |
41 | export const toVec2 = value => toVec(value, Vector2, ({ x, y }) => [x, y]);
42 |
43 | export const vec3 = {
44 | validator: value => vecValidator(value, Vector3),
45 | default: () => Vector3.Zero(),
46 | };
47 |
48 | export const toVec3 = value => toVec(value, Vector3, ({ x, y, z }) => [x, y, z]);
49 |
50 | export const vec4 = {
51 | validator: value => vecValidator(value, Vector4),
52 | default: () => Vector4.Zero(),
53 | };
54 |
55 | export const toVec4 = value => toVec(value, Vector4, ({ w, x, y, z }) => [w, x, y, z]);
56 |
57 | export const $vector = (...value) => {
58 | if (Array.isArray(value[0])) {
59 | [value] = value;
60 | }
61 | if (vecValidator(value, Vector4)) {
62 | return toVec4(value);
63 | } else if (vecValidator(value, Vector3)) {
64 | return toVec3(value);
65 | }
66 | return toVec2(value);
67 | };
68 |
--------------------------------------------------------------------------------
/src/util/index.js:
--------------------------------------------------------------------------------
1 | export const isFloat = value => Number.isFinite(value) && !Number.isNaN(value);
2 |
3 | export const isFloatArray = value => Array.isArray(value) && value.every(isFloat);
4 |
5 | export const isBetween0and1 = value => isFloat(value) && value <= 1 && value >= 0;
6 |
7 | export const id = (size = 12) => {
8 | let buf = new Uint8Array(size);
9 | window.crypto.getRandomValues(buf);
10 | return btoa(String.fromCharCode(...buf)).replace(/\//g, '_').replace(/\+/g, '-');
11 | };
12 |
13 | export const capitalize = ([first, ...rest]) => first.toUpperCase() + rest.join('');
14 |
15 | export const isPercent = value => {
16 | value = Number.parseFloat(value);
17 | return !Number.isNaN(value) && value >= 0 && value <= 100;
18 | };
19 |
20 | export const isDisposable = entity => entity && typeof entity.dispose === 'function';
21 |
22 | export const createBus = function () {
23 | let Vue = this.constructor.super;
24 | return new Vue();
25 | };
26 |
27 | export const camelize = str => str.split('-').reduce((result, [first, ...rest]) => result + first.toUpperCase() + rest.join(''), '');
28 |
29 | export const last = ([...arr]) => arr.pop();
30 |
31 | export const defer = () => {
32 | let split;
33 | let promise = new Promise((...args) => {
34 | split = args;
35 | });
36 | let [complete, error] = split;
37 | Object.assign(promise, { complete, error });
38 | return promise;
39 | };
40 |
--------------------------------------------------------------------------------
/src/util/test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import { camelize } from './';
3 |
4 | const CAMEL = 'SomeNameValue';
5 | let camelizeMacro = (t, input) => t.is(camelize(input), CAMEL);
6 | camelizeMacro.title = title => `camelize ${title}`;
7 | test('kebab case', camelizeMacro, 'some-name-value');
8 | test('already upper camelcase', camelizeMacro, 'SomeNameValue');
9 | test('lower camelcase', camelizeMacro, 'someNameValue');
10 |
--------------------------------------------------------------------------------