├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── docs ├── controls_src_index.js.html ├── core_src_index.js.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ └── OpenSans-Regular-webfont.woff ├── geometries_src_index.js.html ├── index.html ├── module-controls.html ├── module-core.html ├── module-geometries.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js └── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css ├── jsdoc.config.json ├── package-lock.json ├── package.json ├── packages ├── controls │ ├── README.md │ ├── build │ │ ├── controls.js │ │ ├── controls.min.js │ │ └── controls.module.js │ ├── package.json │ └── src │ │ ├── index.js │ │ ├── orbit │ │ └── index.js │ │ └── utils │ │ └── math.js ├── core │ ├── README.md │ ├── build │ │ ├── core.js │ │ ├── core.min.js │ │ └── core.module.js │ ├── package.json │ └── src │ │ ├── cameras │ │ ├── index.js │ │ ├── orthographic.js │ │ └── perspective.js │ │ ├── constants.js │ │ ├── core │ │ ├── composer.js │ │ ├── lights.js │ │ ├── mesh.js │ │ ├── model.js │ │ ├── object3.js │ │ ├── pass.js │ │ ├── performance.js │ │ ├── renderer.js │ │ ├── rt.js │ │ ├── scene.js │ │ ├── shadow-map-renderer.js │ │ ├── texture.js │ │ └── vector3.js │ │ ├── gl │ │ ├── attributes.js │ │ ├── index.js │ │ ├── program.js │ │ ├── types.js │ │ ├── ubo.js │ │ ├── uniforms.js │ │ └── vao.js │ │ ├── helpers │ │ ├── axis.js │ │ ├── index.js │ │ └── normal.js │ │ ├── index.js │ │ ├── passes │ │ ├── basic.js │ │ └── index.js │ │ ├── session.js │ │ ├── shaders │ │ ├── basic.js │ │ ├── billboard.js │ │ ├── chunks │ │ │ ├── clipping.js │ │ │ ├── extensions.js │ │ │ ├── fog.js │ │ │ ├── index.js │ │ │ ├── light.js │ │ │ ├── noise.js │ │ │ ├── shadow.js │ │ │ └── ubo.js │ │ ├── default.js │ │ ├── index.js │ │ └── sem.js │ │ └── utils │ │ ├── color.js │ │ ├── dom.js │ │ ├── glsl-parser.js │ │ ├── index.js │ │ └── math.js ├── geometries │ ├── README.md │ ├── build │ │ ├── geometries.js │ │ ├── geometries.min.js │ │ └── geometries.module.js │ ├── package.json │ └── src │ │ ├── box │ │ └── index.js │ │ ├── dodecahedron │ │ └── index.js │ │ ├── hexahedron │ │ └── index.js │ │ ├── icosahedron │ │ └── index.js │ │ ├── index.js │ │ ├── octahedron │ │ └── index.js │ │ ├── plane │ │ └── index.js │ │ ├── polyhedra.js │ │ ├── prism │ │ └── index.js │ │ ├── sphere │ │ └── index.js │ │ ├── tetrahedron │ │ └── index.js │ │ ├── torus │ │ └── index.js │ │ ├── torusknot │ │ └── index.js │ │ └── utils │ │ ├── index.js │ │ ├── merge.js │ │ └── modify.js ├── physics │ ├── README.md │ ├── build │ │ ├── physics.js │ │ ├── physics.min.js │ │ └── physics.module.js │ ├── package.json │ └── src │ │ ├── colliders │ │ ├── aabb-collider.js │ │ └── sphere-collider.js │ │ ├── constants.js │ │ ├── core │ │ ├── contacts.js │ │ ├── force.js │ │ ├── rigid-body.js │ │ └── world.js │ │ ├── index.js │ │ └── workers │ │ └── todo.js └── postprocessing │ ├── README.md │ ├── build │ ├── postprocessing.js │ ├── postprocessing.min.js │ └── postprocessing.module.js │ ├── package.json │ └── src │ ├── bleach │ └── index.js │ ├── blur │ ├── horizontal.js │ ├── index.js │ └── vertical.js │ ├── brightness │ └── index.js │ ├── dot-screen │ └── index.js │ ├── glitch │ └── index.js │ ├── hue-saturation │ └── index.js │ ├── index.js │ ├── noise │ └── index.js │ └── tilt-shift │ ├── horizontal.js │ ├── index.js │ └── vertical.js ├── scripts ├── node │ ├── generate-packages.js │ └── minify-options.js └── rollup │ ├── examples.development.js │ ├── examples.production.js │ ├── rollup-plugins │ ├── copy.js │ └── html.js │ ├── rollup.es5.js │ └── rollup.es6.js ├── site ├── basic.html ├── clipping-planes.html ├── css │ └── style.css ├── favicon.ico ├── geometries.html ├── img │ ├── facebook.png │ ├── logo.svg │ ├── matcap │ │ ├── black-gloss.jpg │ │ ├── skin.jpg │ │ └── world.jpg │ ├── thumbnails │ │ ├── basic.jpg │ │ ├── clipping-planes.jpg │ │ ├── geometries.jpg │ │ ├── instancing.jpg │ │ ├── materials.jpg │ │ ├── modify.jpg │ │ ├── postprocessing.jpg │ │ └── render-to-texture.jpg │ ├── twitter.png │ └── uv.png ├── index.html ├── instancing.html ├── js │ ├── basic.js │ ├── clipping-planes.js │ ├── geometries.js │ ├── instancing.js │ ├── materials.js │ ├── modify.js │ ├── physics.js │ ├── postprocessing.js │ └── render-to-texture.js ├── materials.html ├── modify.html ├── physics.html ├── postprocessing.html └── render-to-texture.html └── src ├── _physics └── index.js ├── _prism ├── index.js └── letters.js ├── basic └── index.js ├── clipping-planes └── index.js ├── geometries └── index.js ├── instancing └── index.js ├── materials └── index.js ├── modify └── index.js ├── postprocessing └── index.js ├── render-to-texture └── index.js ├── static ├── css │ └── style.css ├── favicon.ico └── img │ ├── facebook.png │ ├── logo.svg │ ├── matcap │ ├── black-gloss.jpg │ ├── skin.jpg │ └── world.jpg │ ├── thumbnails │ ├── 2d-pattern3.jpg │ ├── 2d-pattern3.png │ ├── basic.jpg │ ├── clipping-planes.jpg │ ├── geometries.jpg │ ├── instancing.jpg │ ├── materials.jpg │ ├── modify.jpg │ ├── postprocessing.jpg │ └── render-to-texture.jpg │ ├── twitter.png │ └── uv.png └── template.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }] 6 | ], 7 | "plugins": [ 8 | "external-helpers", 9 | "transform-class-properties" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | packages/controls/build 3 | packages/core/build 4 | packages/geometries/build 5 | packages/postprocessing/build 6 | packages/physics/build 7 | site/ 8 | dev/ 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": ["airbnb", "prettier"], 4 | "globals": { 5 | "__LIBRARY__": true, 6 | "__VERSION__": true, 7 | "cancelAnimationFrame": true, 8 | "document": true, 9 | "Image": true, 10 | "lowww": true, 11 | "requestAnimationFrame": true, 12 | "window": true 13 | }, 14 | "rules": { 15 | "arrow-body-style": [0], 16 | "class-methods-use-this": [0], 17 | "global-require": [0], 18 | "guard-for-in": [0], 19 | "import/prefer-default-export": [0], 20 | "indent": [2, 4], 21 | "no-bitwise": [0], 22 | "no-console": [0], 23 | "no-param-reassign": [0], 24 | "no-plusplus": [0], 25 | "no-restricted-syntax": [2, 'DebuggerStatement'], 26 | "no-return-assign": [0], 27 | "no-underscore-dangle": [0], 28 | "prefer-destructuring": ["error", { "array": false, "object": true }, { "enforceForRenamedProperties": false }] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | scripts/minify-options.json 3 | dev/* 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "semi": true, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8.9.4" 4 | script: 5 | - npm run lint:all 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2018 André Venâncio (info@andrevenancio.com) 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 |

2 | icon 3 |

4 |

lowww `WebGL2.0` engine

5 | 6 | lowww 7 | === 8 | licence 9 | Travis Status 10 | Dependency Status 11 | devDependency Status 12 | 13 | lowww is a `WebGL 2.0` Javascript 3D engine. This is an experimental project focused in the advantages of `WebGL 2.0` and `GLSL ES 3.0`. It falls back to `WebGL` for devices that don't yet support `WebGL 2.0`. 14 | 15 | 16 | ## About this repository 17 | This is a monorepo where all packages are separated in the `packages/` folder and they can be imported independently as a npm module. There are several [npm scripts](https://github.com/andrevenancio/lowww/blob/master/package.json#L13) to allow you to build each module independently. 18 | 19 | A brief explanation of the content within this monorepo can be seen below: 20 | * `packages/` - contains all the packages part of the engine. Each package is a separate npm module. 21 | * `scripts/` - contains all the build scripts necessary to compile the website, examples, documentation and each individual package. 22 | * `site/` - contains the source code of the website. 23 | * `src/` - contains the source code for the website which include the examples. This is where you should add any specific example you might want to contribute. 24 | 25 | 26 | ## Development 27 | `npm start` 28 | 29 | 30 | ## Production 31 | `npm build:all` 32 | -------------------------------------------------------------------------------- /docs/controls_src_index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: controls/src/index.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: controls/src/index.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Controls
31 |  * @module controls
32 |  */
33 | 
34 | import Orbit from './orbit';
35 | 
36 | export { Orbit };
37 | 
38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 | 46 | 49 | 50 |
51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/core_src_index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: core/src/index.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: core/src/index.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Core
31 |  * @module core
32 |  */
33 | import * as chunks from './shaders/chunks';
34 | import * as utils from './utils';
35 | import * as cameras from './cameras';
36 | import * as shaders from './shaders';
37 | import * as helpers from './helpers';
38 | import * as constants from './constants';
39 | 
40 | import Renderer from './core/renderer';
41 | import Object3 from './core/object3';
42 | import Scene from './core/scene';
43 | import Model from './core/model';
44 | import Mesh from './core/mesh';
45 | import Texture from './core/texture';
46 | import RenderTarget from './core/rt';
47 | import Composer from './core/composer';
48 | import Pass from './core/pass';
49 | import Performance from './core/performance';
50 | 
51 | export {
52 |     chunks,
53 |     utils,
54 |     cameras,
55 |     shaders,
56 |     helpers,
57 |     constants,
58 |     Renderer,
59 |     Object3,
60 |     Scene,
61 |     Model,
62 |     Mesh,
63 |     Texture,
64 |     RenderTarget,
65 |     Composer,
66 |     Pass,
67 |     Performance,
68 | };
69 | 
70 |
71 |
72 | 73 | 74 | 75 | 76 |
77 | 78 | 81 | 82 |
83 | 84 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/geometries_src_index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: geometries/src/index.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: geometries/src/index.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  * Geometries
31 |  * @module geometries
32 |  */
33 | import * as utils from './utils';
34 | 
35 | import Tetrahedron from './tetrahedron';
36 | import Hexahedron from './hexahedron';
37 | import Octahedron from './octahedron';
38 | import Dodecahedron from './dodecahedron';
39 | import Icosahedron from './icosahedron';
40 | 
41 | import Plane from './plane';
42 | import Box from './box';
43 | import Sphere from './sphere';
44 | import Torus from './torus';
45 | import TorusKnot from './torusknot';
46 | 
47 | export {
48 |     utils,
49 | 
50 |     /* PLATONIC SOLIDS */
51 |     Tetrahedron,
52 |     Hexahedron,
53 |     Octahedron,
54 |     Dodecahedron,
55 |     Icosahedron,
56 | 
57 |     /* OTHER */
58 |     Plane,
59 |     Box,
60 |     Sphere,
61 |     Torus,
62 |     TorusKnot,
63 | };
64 | 
65 |
66 |
67 | 68 | 69 | 70 | 71 |
72 | 73 | 76 | 77 |
78 | 79 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 55 | 56 |
57 | 58 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/module-controls.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Module: controls 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Module: controls

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 |
Controls
42 | 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 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
Source:
89 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
142 | 143 |
144 | 145 | 146 | 147 | 148 |
149 | 150 | 153 | 154 |
155 | 156 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /docs/module-core.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Module: core 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Module: core

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 |
Core
42 | 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 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
Source:
89 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
142 | 143 |
144 | 145 | 146 | 147 | 148 |
149 | 150 | 153 | 154 |
155 | 156 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /docs/module-geometries.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Module: geometries 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Module: geometries

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 |
Geometries
42 | 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 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
Source:
89 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
142 | 143 |
144 | 145 | 146 | 147 | 148 |
149 | 150 | 153 | 154 |
155 | 156 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /jsdoc.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "include": [ 4 | "packages/controls/src/index.js", 5 | "packages/core/src/index.js", 6 | "packages/geometries/src/index.js", 7 | "packages/postprocessing/src/index.js" 8 | ] 9 | }, 10 | "opts": { 11 | "recurse": true, 12 | "destination": "./docs/" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/controls/README.md: -------------------------------------------------------------------------------- 1 | # lowww-controls 2 | Adds camera control utilities for the [lowww](https://github.com/andrevenancio/lowww) engine. 3 | 4 | ## Installation 5 | `npm install --save lowww-controls` 6 | 7 | 8 | ## Usage 9 | ```javascript 10 | import { Renderer, Scene, cameras, Mesh } from 'lowww-core'; 11 | import { Box } from 'lowww-geometries'; 12 | import { Orbit } from 'lowww-controls'; 13 | 14 | let renderer; 15 | let camera; 16 | let scene; 17 | let controls; 18 | let mesh; 19 | 20 | init(); 21 | update(); 22 | 23 | const init = () => { 24 | renderer = new Renderer(); 25 | renderer.setSize(400, 300); 26 | document.body.appendChild(renderer.domElement); 27 | 28 | camera = new cameras.Perspective(); 29 | camera.position.set(0, 0, 500); 30 | 31 | scene = new Scene(); 32 | 33 | controls = new Orbit(camera, renderer.domElement); 34 | 35 | const geometry = new Box({ width: 10, height: 10, depth: 10 }); 36 | mesh = new Mesh({ geometry }); 37 | scene.add(mesh); 38 | }; 39 | 40 | const update = () => { 41 | controls.update(); 42 | renderer.render(scene, camera); 43 | requestAnimationFrame(update.bind(this)); 44 | }; 45 | ``` 46 | 47 | 48 | ## License 49 | MIT 50 | -------------------------------------------------------------------------------- /packages/controls/build/controls.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | lowww-controls - version: 1.1.5 3 | Copyright © 2018 Andre Venancio (info@andrevenancio.com) 4 | */ 5 | var t,e;t=this,e=function(t){"use strict";var o="undefined"!=typeof Float32Array?Float32Array:Array;function e(){var t=new o(3);return t[0]=0,t[1]=0,t[2]=0,t}function n(t,e,n){var i=new o(3);return i[0]=t,i[1]=e,i[2]=n,i}Math.PI;var i;function s(){var t=new o(4);return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t}e(),(i=new o(4))[0]=0,i[1]=0,i[2]=0,i[3]=0;var r,h;function a(t,e,n){return Math.max(Math.min(t,n),e)}e(),n(1,0,0),n(0,1,0),s(),s(),(r=new o(9))[0]=1,r[1]=0,r[2]=0,r[3]=0,r[4]=1,r[5]=0,r[6]=0,r[7]=0,r[8]=1,(h=new o(2))[0]=0,h[1]=0;var d=function(){function i(t,e){for(var n=0;nr.oldDiff?-100:100,r.zoom(s),r.oldDiff=r.curDiff}}},this.onEnd=function(){r.isDown=!1,r.oldDiff=-1},this.onWheel=function(t){t.preventDefault(),r.zoom(-t.deltaY)},this.camera=t,this.domElement=e,this.radius=Math.max(t.position.x,t.position.z),this.rx=Math.atan2(t.position.y,this.radius),this.ry=Math.atan2(t.position.z,t.position.x)+u,this.ox=0,this.oy=0,this.width=window.innerWidth,this.height=window.innerHeight,this.rotationSpeed=5*window.devicePixelRatio,this.zoomMin=.1,this.zoomMax=1/0,this.zoomSpeed=100,this.isDown=!1,this.curDiff=0,this.oldDiff=-1,this.enable()}return d(n,[{key:"enable",value:function(){this.domElement.addEventListener("mousedown",this.onStart,!1),this.domElement.addEventListener("mousemove",this.onMove,!1),this.domElement.addEventListener("mouseup",this.onEnd,!1),this.domElement.addEventListener("touchstart",this.onStart,!1),this.domElement.addEventListener("touchmove",this.onMove,!1),this.domElement.addEventListener("touchend",this.onEnd,!1),this.domElement.addEventListener("wheel",this.onWheel,!1)}},{key:"disable",value:function(){this.domElement.removeEventListener("mousedown",this.onStart,!1),this.domElement.removeEventListener("mousemove",this.onMove,!1),this.domElement.removeEventListener("mouseup",this.onEnd,!1),this.domElement.removeEventListener("touchstart",this.onStart,!1),this.domElement.removeEventListener("touchmove",this.onMove,!1),this.domElement.removeEventListener("touchend",this.onEnd,!1),this.domElement.removeEventListener("wheel",this.onWheel,!1)}},{key:"pinchMode",value:function(t,e,n,i){return Math.sqrt((t-n)*(t-n)+(e-i)*(e-i))}},{key:"zoom",value:function(t){this.radius+=t/1e3*this.zoomSpeed,this.radius=a(this.radius,this.zoomMin,this.zoomMax)}},{key:"update",value:function(){var t,e,n,i,o=this.radius*Math.sin(this.rx),s=this.radius*Math.cos(this.rx);e=Math.sin(this.ry)*s,n=o,i=Math.cos(this.ry)*s,(t=this.camera.position.data)[0]=e,t[1]=n,t[2]=i}}]),n}();t.Orbit=m,Object.defineProperty(t,"__esModule",{value:!0})},"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t.lowww=t.lowww||{},t.lowww.controls={})); 6 | -------------------------------------------------------------------------------- /packages/controls/package.json: -------------------------------------------------------------------------------- 1 | {"name":"lowww-controls","description":"WebGL 2 Engine extension","author":"Andre Venancio (info@andrevenancio.com)","version":"1.1.5","main":"src/index.js","module":"build/controls.module.js","repository":"git@github.com:andrevenancio/lowww.git","scripts":{"test":"echo 'Error: no test specified' && exit 0"},"devDependencies":{},"dependencies":{"gl-matrix":"^2.5.1"}} -------------------------------------------------------------------------------- /packages/controls/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Controls 3 | * @module controls 4 | */ 5 | 6 | import Orbit from './orbit'; 7 | 8 | export { Orbit }; 9 | -------------------------------------------------------------------------------- /packages/controls/src/utils/math.js: -------------------------------------------------------------------------------- 1 | export function clamp(value, min, max) { 2 | return Math.max(Math.min(value, max), min); 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # lowww-core 2 | core functionality for the [lowww](https://github.com/andrevenancio/lowww) engine. 3 | 4 | ## Installation 5 | `npm install --save lowww-core` 6 | 7 | 8 | ## Usage 9 | ```javascript 10 | import { Renderer, Scene, cameras, Mesh } from 'lowww-core'; 11 | import { Box } from 'lowww-geometries'; 12 | 13 | let renderer; 14 | let camera; 15 | let scene; 16 | let mesh; 17 | 18 | init(); 19 | update(); 20 | 21 | const init = () => { 22 | renderer = new Renderer(); 23 | renderer.setSize(400, 300); 24 | document.body.appendChild(renderer.domElement); 25 | 26 | camera = new cameras.Perspective(); 27 | camera.position.set(0, 0, 500); 28 | 29 | scene = new Scene(); 30 | 31 | const geometry = new Box({ width: 10, height: 10, depth: 10 }); 32 | mesh = new Mesh({ geometry }); 33 | scene.add(mesh); 34 | }; 35 | 36 | const update = () => { 37 | mesh.rotation.x += 0.01; 38 | mesh.rotation.y += 0.01; 39 | 40 | renderer.render(scene, camera); 41 | requestAnimationFrame(update.bind(this)); 42 | }; 43 | ``` 44 | 45 | ## Hello World 46 | check out this [JSFiddle](https://jsfiddle.net/andrevenancio/Lq1wgvjp/). 47 | 48 | ## License 49 | MIT 50 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | {"name":"lowww-core","description":"WebGL 2 Engine extension","author":"Andre Venancio (info@andrevenancio.com)","version":"1.1.5","main":"src/index.js","module":"build/core.module.js","repository":"git@github.com:andrevenancio/lowww.git","scripts":{"test":"echo 'Error: no test specified' && exit 0"},"devDependencies":{},"dependencies":{"gl-matrix":"^2.5.1"}} -------------------------------------------------------------------------------- /packages/core/src/cameras/index.js: -------------------------------------------------------------------------------- 1 | import Orthographic from './orthographic'; 2 | import Perspective from './perspective'; 3 | 4 | export { Orthographic, Perspective }; 5 | -------------------------------------------------------------------------------- /packages/core/src/cameras/orthographic.js: -------------------------------------------------------------------------------- 1 | import { vec3, mat4 } from 'gl-matrix'; 2 | import Object3 from '../core/object3'; 3 | 4 | class OrthographicCamera extends Object3 { 5 | constructor(params = {}) { 6 | super(); 7 | 8 | Object.assign( 9 | this, 10 | { 11 | left: -1, 12 | right: 1, 13 | top: 1, 14 | bottom: -1, 15 | near: -1000, 16 | far: 1000, 17 | }, 18 | params 19 | ); 20 | 21 | this.matrices.projection = mat4.create(); 22 | } 23 | 24 | lookAt(v) { 25 | vec3.copy(this.target, v); 26 | } 27 | 28 | /** 29 | * updates projection matrix 30 | * 31 | * @param {Number} a The first number to test. 32 | * @param {Number} b The second number to test. 33 | * @returns {Boolean} True if the numbers are approximately equal, false otherwise. 34 | */ 35 | updateCameraMatrix() { 36 | // left, right, bottom, top, near, far 37 | mat4.ortho( 38 | this.matrices.projection, 39 | this.left, 40 | this.right, 41 | this.bottom, 42 | this.top, 43 | this.near, 44 | this.far 45 | ); 46 | } 47 | } 48 | 49 | export default OrthographicCamera; 50 | -------------------------------------------------------------------------------- /packages/core/src/cameras/perspective.js: -------------------------------------------------------------------------------- 1 | import { vec3, mat4 } from 'gl-matrix'; 2 | import Object3 from '../core/object3'; 3 | 4 | class PerspectiveCamera extends Object3 { 5 | constructor(params = {}) { 6 | super(); 7 | 8 | Object.assign( 9 | this, 10 | { 11 | near: 1, 12 | far: 1000, 13 | fov: 35, 14 | }, 15 | params 16 | ); 17 | 18 | this.matrices.projection = mat4.create(); 19 | } 20 | 21 | lookAt(v) { 22 | vec3.copy(this.target, v); 23 | } 24 | 25 | updateCameraMatrix(width, height) { 26 | mat4.perspective( 27 | this.matrices.projection, 28 | this.fov * (Math.PI / 180), 29 | width / height, 30 | this.near, 31 | this.far 32 | ); 33 | } 34 | } 35 | 36 | export default PerspectiveCamera; 37 | -------------------------------------------------------------------------------- /packages/core/src/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Max directional light allowed 3 | * 4 | * @static 5 | * @constant 6 | * @name MAX_DIRECTIONAL 7 | * @type {string} 8 | */ 9 | export const MAX_DIRECTIONAL = 1; 10 | 11 | /** 12 | * directional light id 13 | * 14 | * @static 15 | * @constant 16 | * @name DIRECTIONAL_LIGHT 17 | * @type {string} 18 | */ 19 | export const DIRECTIONAL_LIGHT = 1000; 20 | 21 | /** 22 | * basic shader id 23 | * 24 | * @static 25 | * @constant 26 | * @name SHADER_BASIC 27 | * @type {string} 28 | */ 29 | export const SHADER_BASIC = 2000; 30 | 31 | /** 32 | * default shader id 33 | * 34 | * @static 35 | * @constant 36 | * @name SHADER_DEFAULT 37 | * @type {string} 38 | */ 39 | export const SHADER_DEFAULT = 2001; 40 | 41 | /** 42 | * billboard shader id 43 | * 44 | * @static 45 | * @constant 46 | * @name SHADER_BILLBOARD 47 | * @type {string} 48 | */ 49 | export const SHADER_BILLBOARD = 2002; 50 | 51 | /** 52 | * shadow shader id 53 | * 54 | * @static 55 | * @constant 56 | * @name SHADER_SHADOW 57 | * @type {string} 58 | */ 59 | export const SHADER_SHADOW = 2003; 60 | 61 | /** 62 | * sem shader id 63 | * 64 | * @static 65 | * @constant 66 | * @name SHADER_SEM 67 | * @type {string} 68 | */ 69 | export const SHADER_SEM = 2004; 70 | 71 | /** 72 | * custom shader id 73 | * 74 | * @static 75 | * @constant 76 | * @name SHADER_CUSTOM 77 | * @type {string} 78 | */ 79 | export const SHADER_CUSTOM = 2500; 80 | 81 | /** 82 | * shader draw modes 83 | * 84 | * @static 85 | * @constant 86 | * @name DRAW 87 | * @type {object} 88 | * @property {number} POINTS 89 | * @property {number} LINES 90 | * @property {number} TRIANGLES 91 | */ 92 | export const DRAW = { 93 | POINTS: 0, 94 | LINES: 1, 95 | TRIANGLES: 4, 96 | }; 97 | 98 | /** 99 | * triangle side 100 | * 101 | * @static 102 | * @constant 103 | * @name SIDE 104 | * @type {object} 105 | * @property {number} FRONT 106 | * @property {number} BACK 107 | * @property {number} BOTH 108 | */ 109 | export const SIDE = { 110 | FRONT: 0, 111 | BACK: 1, 112 | BOTH: 2, 113 | }; 114 | 115 | /** 116 | * context types 117 | * 118 | * @static 119 | * @constant 120 | * @name CONTEXT 121 | * @type {object} 122 | * @property {number} WEBGL 123 | * @property {number} WEBGL2 124 | */ 125 | export const CONTEXT = { 126 | WEBGL: 'webgl', 127 | WEBGL2: 'webgl2', 128 | }; 129 | -------------------------------------------------------------------------------- /packages/core/src/core/composer.js: -------------------------------------------------------------------------------- 1 | import { vec4 } from 'gl-matrix'; 2 | import { Orthographic } from '../cameras'; 3 | import Renderer from './renderer'; 4 | import RenderTarget from './rt'; 5 | import Pass from './pass'; 6 | import { Basic } from '../passes'; 7 | 8 | class Composer { 9 | constructor(props) { 10 | this.renderer = new Renderer(props); 11 | this.domElement = this.renderer.domElement; 12 | 13 | this.camera = new Orthographic(); 14 | this.camera.position.z = 100; 15 | 16 | this.passes = []; 17 | 18 | this.clearColor = vec4.fromValues(0, 0, 0, 1); 19 | 20 | this.screen = new Pass(Basic); 21 | this.screen.compile(); 22 | 23 | this.buffers = [new RenderTarget(), new RenderTarget()]; 24 | 25 | this.read = this.buffers[1]; 26 | this.write = this.buffers[0]; 27 | } 28 | 29 | setSize(width, height) { 30 | this.renderer.setSize(width, height); 31 | this.read.setSize(width, height); 32 | this.write.setSize(width, height); 33 | } 34 | 35 | setRatio(ratio) { 36 | this.renderer.setRatio(ratio); 37 | } 38 | 39 | pass(pass) { 40 | this.passes.push(pass); 41 | } 42 | 43 | compile() { 44 | for (let i = 0; i < this.passes.length; i++) { 45 | this.passes[i].compile(); 46 | } 47 | } 48 | 49 | renderToTexture(renderTarget, scene, camera) { 50 | this.renderer.rtt({ 51 | renderTarget, 52 | scene, 53 | camera, 54 | clearColor: this.clearColor, 55 | }); 56 | } 57 | 58 | resetBuffers() { 59 | this.read = this.buffers[1]; 60 | this.write = this.buffers[0]; 61 | } 62 | 63 | swapBuffers() { 64 | this.temp = this.read; 65 | this.read = this.write; 66 | this.write = this.temp; 67 | } 68 | 69 | render(scene, camera) { 70 | this.resetBuffers(); 71 | this.renderToTexture(this.write, scene, camera); 72 | 73 | // ping pong textures through passes 74 | const total = this.passes.length; 75 | for (let i = 0; i < total; i++) { 76 | if (this.passes[i].enable) { 77 | this.swapBuffers(); 78 | this.passes[i].setUniform('u_input', this.read.texture); 79 | this.renderToTexture( 80 | this.write, 81 | this.passes[i].scene, 82 | this.camera 83 | ); 84 | } 85 | } 86 | 87 | // render last pass to screen 88 | this.screen.setUniform('u_input', this.write.texture); 89 | this.renderer.render(this.screen.scene, this.camera); 90 | } 91 | } 92 | 93 | export default Composer; 94 | -------------------------------------------------------------------------------- /packages/core/src/core/lights.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | // import Vector3 from '../core/vector3'; 3 | import { DIRECTIONAL_LIGHT } from '../constants'; 4 | 5 | class Light { 6 | constructor() { 7 | this.position = vec3.create(); 8 | } 9 | 10 | destroy() { 11 | // TODO 12 | } 13 | } 14 | 15 | class Directional extends Light { 16 | constructor(props = {}) { 17 | super(); 18 | 19 | this.type = DIRECTIONAL_LIGHT; 20 | 21 | this.color = props.color || vec3.fromValues(1, 1, 1); 22 | this.intensity = props.intensity || 0.989; 23 | } 24 | } 25 | 26 | export { Directional }; 27 | -------------------------------------------------------------------------------- /packages/core/src/core/mesh.js: -------------------------------------------------------------------------------- 1 | import Model from './model'; 2 | import { Default } from '../shaders'; 3 | import { SHADER_CUSTOM } from '../constants'; 4 | 5 | let shaderID = 0; 6 | class Mesh extends Model { 7 | constructor(params = {}) { 8 | super(); 9 | 10 | this._shader = null; 11 | 12 | const { positions, indices, normals, uvs } = params.geometry || {}; 13 | 14 | const { vertex, fragment, uniforms, type, mode } = 15 | params.shader || 16 | new Default({ color: params.color, map: params.map }); 17 | 18 | // if there's a type, assign it, so we can sort by type in the renderer. 19 | if (type !== undefined) { 20 | this.type = type; 21 | } else { 22 | this.type = `${SHADER_CUSTOM}-${shaderID++}`; 23 | } 24 | 25 | if (mode !== undefined) { 26 | this.mode = mode; 27 | } 28 | 29 | this.setAttribute('a_position', 'vec3', new Float32Array(positions)); 30 | if (indices) { 31 | this.setIndex(new Uint16Array(indices)); 32 | } 33 | if (normals) { 34 | this.setAttribute('a_normal', 'vec3', new Float32Array(normals)); 35 | } 36 | if (uvs) { 37 | this.setAttribute('a_uv', 'vec2', new Float32Array(uvs)); 38 | } 39 | 40 | Object.keys(uniforms).forEach(key => { 41 | this.setUniform(key, uniforms[key].type, uniforms[key].value); 42 | }); 43 | 44 | this.setShader(vertex, fragment); 45 | } 46 | 47 | set shader(shader) { 48 | this.dirty.shader = true; 49 | this._shader = shader; 50 | if (shader.type !== undefined) { 51 | this.type = shader.type; 52 | } else { 53 | this.type = SHADER_CUSTOM; 54 | } 55 | this.setShader(shader.vertex, shader.fragment); 56 | } 57 | 58 | get shader() { 59 | return this._shader; 60 | } 61 | } 62 | 63 | export default Mesh; 64 | -------------------------------------------------------------------------------- /packages/core/src/core/pass.js: -------------------------------------------------------------------------------- 1 | import Scene from './scene'; 2 | import Mesh from './mesh'; 3 | import { UBO } from '../shaders/chunks'; 4 | 5 | class Pass { 6 | constructor(props) { 7 | this.scene = new Scene(); 8 | 9 | const { vertex, fragment, uniforms } = props; 10 | 11 | this.vertex = vertex; 12 | this.fragment = fragment; 13 | this.uniforms = uniforms; 14 | 15 | this.enable = true; 16 | } 17 | 18 | compile() { 19 | const shader = { 20 | vertex: `#version 300 es 21 | in vec3 a_position; 22 | in vec3 a_normal; 23 | in vec2 a_uv; 24 | 25 | ${UBO.scene()} 26 | ${UBO.model()} 27 | 28 | ${this.vertex}`, 29 | 30 | fragment: `#version 300 es 31 | precision highp float; 32 | precision highp int; 33 | 34 | ${UBO.scene()} 35 | ${UBO.model()} 36 | 37 | out vec4 outColor; 38 | ${this.fragment}`, 39 | uniforms: this.uniforms, 40 | }; 41 | 42 | const geometry = { 43 | positions: [-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0], 44 | indices: [0, 1, 2, 0, 2, 3], 45 | uvs: [0, 0, 1, 0, 1, 1, 0, 1], 46 | }; 47 | this.quad = new Mesh({ geometry, shader }); 48 | this.scene.add(this.quad); 49 | } 50 | 51 | setUniform(key, value) { 52 | this.quad.uniforms[key].value = value; 53 | } 54 | } 55 | 56 | export default Pass; 57 | -------------------------------------------------------------------------------- /packages/core/src/core/performance.js: -------------------------------------------------------------------------------- 1 | class Performance { 2 | constructor(params = {}) { 3 | this.theme = params.theme || { 4 | font: 5 | 'font-family:sans-serif;font-size:xx-small;font-weight:bold;line-height:15px;-moz-osx-font-smoothing: grayscale;-webkit-font-smoothing: antialiased;', 6 | color1: '#242424', 7 | color2: '#2a2a2a', 8 | color3: '#666', 9 | color4: '#999', 10 | }; 11 | 12 | const container = document.createElement('div'); 13 | container.style.cssText = 14 | 'position:fixed;bottom:0;left:0;min-width:80px;opacity:0.9;z-index:10000;'; 15 | 16 | this.holder = document.createElement('div'); 17 | this.holder.style.cssText = `padding:3px;background-color:${this.theme.color1};`; 18 | container.appendChild(this.holder); 19 | 20 | const title = document.createElement('div'); 21 | title.style.cssText = `${this.theme.font};color:${this.theme.color3};`; 22 | title.innerHTML = 'Performance'; 23 | this.holder.appendChild(title); 24 | 25 | this.msTexts = []; 26 | 27 | this.domElement = container; 28 | } 29 | 30 | rebuild(params) { 31 | this.msTexts = []; 32 | Object.keys(params).forEach(key => { 33 | const element = document.createElement('div'); 34 | element.style.cssText = `${this.theme.font};color:${this.theme.color4};background-color:${this.theme.color2};`; 35 | this.holder.appendChild(element); 36 | this.msTexts[key] = element; 37 | }); 38 | } 39 | 40 | update(renderer) { 41 | if ( 42 | Object.keys(this.msTexts).length !== 43 | Object.keys(renderer.performance).length 44 | ) { 45 | this.rebuild(renderer.performance); 46 | } 47 | 48 | Object.keys(renderer.performance).forEach(key => { 49 | this.msTexts[ 50 | key 51 | ].textContent = `${key}: ${renderer.performance[key]}`; 52 | }); 53 | } 54 | } 55 | 56 | export default Performance; 57 | -------------------------------------------------------------------------------- /packages/core/src/core/scene.js: -------------------------------------------------------------------------------- 1 | import { vec4 } from 'gl-matrix'; 2 | import Object3 from './object3'; 3 | import { Directional } from './lights'; 4 | import { DIRECTIONAL_LIGHT } from '../constants'; 5 | 6 | class Scene extends Object3 { 7 | constructor() { 8 | super(); 9 | 10 | this.lights = { 11 | directional: [], 12 | }; 13 | 14 | this.fog = { 15 | enable: false, 16 | color: vec4.fromValues(0, 0, 0, 1), 17 | start: 500, 18 | end: 1000, 19 | density: 0.00025, 20 | }; 21 | 22 | this.clipping = { 23 | enable: false, 24 | planes: [vec4.create(), vec4.create(), vec4.create()], 25 | }; 26 | 27 | // add sun 28 | const directional = new Directional({ 29 | near: 1, 30 | far: 1000, 31 | }); 32 | directional.position[0] = 125; 33 | directional.position[1] = 250; 34 | directional.position[2] = 500; 35 | this.addLight(directional); 36 | } 37 | 38 | addLight(light) { 39 | switch (light.type) { 40 | case DIRECTIONAL_LIGHT: 41 | this.lights.directional.push(light); 42 | break; 43 | default: 44 | // unsupported light 45 | } 46 | } 47 | 48 | removeLight(light) { 49 | const index = this.lights.directional.indexOf(light); 50 | if (index !== -1) { 51 | light.destroy(); 52 | this.lights.directional.splice(index, 1); 53 | } 54 | } 55 | } 56 | 57 | export default Scene; 58 | -------------------------------------------------------------------------------- /packages/core/src/core/shadow-map-renderer.js: -------------------------------------------------------------------------------- 1 | import { vec3, mat4 } from 'gl-matrix'; 2 | import RenderTarget from './rt'; 3 | import Perspective from '../cameras/perspective'; 4 | import Orthographic from '../cameras/orthographic'; 5 | 6 | class ShadowMapRenderer { 7 | constructor(props = {}) { 8 | // size of texture 9 | this.width = props.width || 1024; 10 | this.height = props.height || 1024; 11 | 12 | // create render target 13 | const { width, height } = this; 14 | this.rt = new RenderTarget({ width, height }); 15 | 16 | // matrices 17 | this.matrices = { 18 | view: mat4.create(), 19 | shadow: mat4.create(), 20 | bias: mat4.fromValues( 21 | 0.5, 22 | 0.0, 23 | 0.0, 24 | 0.0, 25 | 0.0, 26 | 0.5, 27 | 0.0, 28 | 0.0, 29 | 0.0, 30 | 0.0, 31 | 0.5, 32 | 0.0, 33 | 0.5, 34 | 0.5, 35 | 0.5, 36 | 1.0 37 | ), 38 | }; 39 | 40 | // origin of directional light 41 | this.camera = new Perspective({ 42 | fov: 60, 43 | near: 1, 44 | far: 1000, 45 | }); 46 | 47 | this.camera = new Orthographic(); 48 | this.camera.position.z = 1; // TODO: remove this when fix lookAt bug on gl-matrix 49 | this.setLightOrigin(props.light || vec3.fromValues(100, 250, 500)); 50 | } 51 | 52 | // move the camera to the light position 53 | setLightOrigin(vec) { 54 | // CAMERA 55 | 56 | // update camera position 57 | vec3.copy(this.camera.position.data, vec); 58 | 59 | // update view matrix 60 | mat4.identity(this.matrices.view); 61 | mat4.lookAt( 62 | this.matrices.view, 63 | this.camera.position.data, 64 | this.camera.target, 65 | this.camera.up 66 | ); 67 | 68 | // SHADOW 69 | mat4.identity(this.matrices.shadow); 70 | mat4.multiply( 71 | this.matrices.shadow, 72 | this.camera.matrices.projection, 73 | this.matrices.view 74 | ); 75 | mat4.multiply( 76 | this.matrices.shadow, 77 | this.matrices.bias, 78 | this.matrices.shadow 79 | ); 80 | } 81 | 82 | /* 83 | TODO: 84 | maybe create a program just for shadows. this avoids having to change program 85 | in complex scenes just to write for the depth buffer. 86 | find a way to bypass the changeProgram on the renderer to accomodate this. 87 | */ 88 | } 89 | 90 | export default ShadowMapRenderer; 91 | -------------------------------------------------------------------------------- /packages/core/src/core/texture.js: -------------------------------------------------------------------------------- 1 | import { getContext } from '../session'; 2 | 3 | class Texture { 4 | constructor(props = {}) { 5 | const gl = getContext(); 6 | 7 | Object.assign( 8 | this, 9 | { 10 | magFilter: gl.NEAREST, 11 | minFilter: gl.NEAREST, 12 | wrapS: gl.CLAMP_TO_EDGE, 13 | wrapT: gl.CLAMP_TO_EDGE, 14 | transparent: false, 15 | }, 16 | props 17 | ); 18 | 19 | const data = new Uint8Array([255, 255, 255, 255]); 20 | this.texture = gl.createTexture(); 21 | gl.bindTexture(gl.TEXTURE_2D, this.texture); 22 | gl.texImage2D( 23 | gl.TEXTURE_2D, 24 | 0, 25 | gl.RGBA, 26 | 1, 27 | 1, 28 | 0, 29 | gl.RGBA, 30 | gl.UNSIGNED_BYTE, 31 | data 32 | ); 33 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter); 34 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter); 35 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS); 36 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT); 37 | if (this.transparent) { 38 | gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); 39 | } 40 | 41 | gl.bindTexture(gl.TEXTURE_2D, null); 42 | } 43 | 44 | fromImage(url) { 45 | const img = new Image(); 46 | img.crossOrigin = ''; 47 | img.onload = () => { 48 | this.update(img); 49 | }; 50 | img.src = url; 51 | } 52 | 53 | update(image) { 54 | const gl = getContext(); 55 | gl.bindTexture(gl.TEXTURE_2D, this.texture); 56 | gl.generateMipmap(gl.TEXTURE_2D); 57 | gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); 58 | gl.texImage2D( 59 | gl.TEXTURE_2D, 60 | 0, 61 | gl.RGBA, 62 | gl.RGBA, 63 | gl.UNSIGNED_BYTE, 64 | image 65 | ); 66 | gl.bindTexture(gl.TEXTURE_2D, null); 67 | } 68 | } 69 | 70 | export default Texture; 71 | -------------------------------------------------------------------------------- /packages/core/src/core/vector3.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | 3 | class Vector3 { 4 | constructor(x = 0, y = 0, z = 0) { 5 | this.data = vec3.fromValues(x, y, z); 6 | } 7 | 8 | set(x, y, z) { 9 | this.x = x; 10 | this.y = y; 11 | this.z = z; 12 | } 13 | 14 | set x(value) { 15 | this.data[0] = value; 16 | } 17 | 18 | get x() { 19 | return this.data[0]; 20 | } 21 | 22 | set y(value) { 23 | this.data[1] = value; 24 | } 25 | 26 | get y() { 27 | return this.data[1]; 28 | } 29 | 30 | set z(value) { 31 | this.data[2] = value; 32 | } 33 | 34 | get z() { 35 | return this.data[2]; 36 | } 37 | } 38 | 39 | export default Vector3; 40 | -------------------------------------------------------------------------------- /packages/core/src/gl/attributes.js: -------------------------------------------------------------------------------- 1 | import { getContext, getContextType, supports } from '../session'; 2 | import { CONTEXT } from '../constants'; 3 | 4 | export const initAttributes = (attributes, program) => { 5 | const gl = getContext(); 6 | 7 | for (const prop in attributes) { 8 | const current = attributes[prop]; 9 | const location = gl.getAttribLocation(program, prop); 10 | 11 | let b = current.buffer; 12 | if (!current.buffer) { 13 | b = gl.createBuffer(); 14 | } 15 | 16 | gl.bindBuffer(gl.ARRAY_BUFFER, b); 17 | gl.bufferData(gl.ARRAY_BUFFER, current.value, gl.STATIC_DRAW); // or DYNAMIC_DRAW 18 | gl.bindBuffer(gl.ARRAY_BUFFER, null); 19 | 20 | Object.assign(current, { 21 | location, 22 | buffer: b, 23 | }); 24 | } 25 | }; 26 | 27 | export const bindAttributes = attributes => { 28 | const gl = getContext(); 29 | 30 | Object.keys(attributes).forEach(key => { 31 | const { location, buffer, size, instanced } = attributes[key]; 32 | 33 | if (location !== -1) { 34 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 35 | gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0); 36 | gl.enableVertexAttribArray(location); 37 | 38 | const divisor = instanced ? 1 : 0; 39 | if (getContextType() === CONTEXT.WEBGL2) { 40 | gl.vertexAttribDivisor(location, divisor); 41 | } else { 42 | supports().instancedArrays.vertexAttribDivisorANGLE( 43 | location, 44 | divisor 45 | ); 46 | } 47 | 48 | gl.bindBuffer(gl.ARRAY_BUFFER, null); 49 | } 50 | }); 51 | }; 52 | 53 | export const updateAttributes = attributes => { 54 | const gl = getContext(); 55 | Object.keys(attributes).forEach(key => { 56 | const { location, buffer, value } = attributes[key]; 57 | 58 | if (location !== -1) { 59 | gl.enableVertexAttribArray(location); 60 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 61 | gl.bufferData(gl.ARRAY_BUFFER, value, gl.DYNAMIC_DRAW); 62 | gl.bindBuffer(gl.ARRAY_BUFFER, null); 63 | } 64 | }); 65 | }; 66 | -------------------------------------------------------------------------------- /packages/core/src/gl/index.js: -------------------------------------------------------------------------------- 1 | import Ubo from './ubo'; 2 | import Vao from './vao'; 3 | import { getTypeSize } from './types'; 4 | import { createProgram } from './program'; 5 | import { initAttributes, bindAttributes, updateAttributes } from './attributes'; 6 | import { initUniforms, updateUniforms } from './uniforms'; 7 | 8 | export { 9 | Ubo, 10 | Vao, 11 | getTypeSize, 12 | createProgram, 13 | initAttributes, 14 | bindAttributes, 15 | updateAttributes, 16 | initUniforms, 17 | updateUniforms, 18 | }; 19 | -------------------------------------------------------------------------------- /packages/core/src/gl/program.js: -------------------------------------------------------------------------------- 1 | const PROGRAM_POOL = {}; 2 | 3 | function createShader(gl, str, type) { 4 | const shader = gl.createShader(type); 5 | 6 | gl.shaderSource(shader, str); 7 | gl.compileShader(shader); 8 | 9 | const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 10 | 11 | if (!compiled) { 12 | const error = gl.getShaderInfoLog(shader); 13 | 14 | gl.deleteShader(shader); 15 | console.error(error, str); 16 | throw new Error(error); 17 | } 18 | 19 | return shader; 20 | } 21 | 22 | export const createProgram = (gl, vertex, fragment, programID) => { 23 | const pool = PROGRAM_POOL[`pool_${programID}`]; 24 | if (!pool) { 25 | const vs = createShader(gl, vertex, gl.VERTEX_SHADER); 26 | const fs = createShader(gl, fragment, gl.FRAGMENT_SHADER); 27 | 28 | const program = gl.createProgram(); 29 | 30 | gl.attachShader(program, vs); 31 | gl.attachShader(program, fs); 32 | gl.linkProgram(program); 33 | 34 | PROGRAM_POOL[`pool_${programID}`] = program; 35 | 36 | return program; 37 | } 38 | 39 | return pool; 40 | }; 41 | -------------------------------------------------------------------------------- /packages/core/src/gl/types.js: -------------------------------------------------------------------------------- 1 | export const getTypeSize = type => { 2 | switch (type) { 3 | case 'float': 4 | return 1; 5 | case 'vec2': 6 | return 2; 7 | case 'vec3': 8 | return 3; 9 | case 'vec4': 10 | case 'mat2': 11 | return 4; 12 | case 'mat3': 13 | return 9; 14 | case 'mat4': 15 | return 16; 16 | default: 17 | throw new Error(`"${type}" is an unknown type`); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /packages/core/src/gl/ubo.js: -------------------------------------------------------------------------------- 1 | import { getContext } from '../session'; 2 | 3 | class Ubo { 4 | constructor(data, boundLocation) { 5 | const gl = getContext(); 6 | this.boundLocation = boundLocation; 7 | 8 | this.data = new Float32Array(data); 9 | 10 | this.buffer = gl.createBuffer(); 11 | gl.bindBuffer(gl.UNIFORM_BUFFER, this.buffer); 12 | gl.bufferData(gl.UNIFORM_BUFFER, this.data, gl.STATIC_DRAW); // DYNAMIC_DRAW 13 | gl.bindBuffer(gl.UNIFORM_BUFFER, null); 14 | } 15 | 16 | bind() { 17 | const gl = getContext(); 18 | gl.bindBufferBase(gl.UNIFORM_BUFFER, this.boundLocation, this.buffer); 19 | // gl.bindBufferBase(gl.UNIFORM_BUFFER, null); // MAYBE? 20 | } 21 | 22 | update(data, offset = 0) { 23 | const gl = getContext(); 24 | 25 | this.data.set(data, offset); 26 | 27 | gl.bindBuffer(gl.UNIFORM_BUFFER, this.buffer); 28 | gl.bufferSubData(gl.UNIFORM_BUFFER, 0, this.data, 0, null); 29 | gl.bindBuffer(gl.UNIFORM_BUFFER, null); 30 | } 31 | } 32 | 33 | export default Ubo; 34 | -------------------------------------------------------------------------------- /packages/core/src/gl/uniforms.js: -------------------------------------------------------------------------------- 1 | import { getContext } from '../session'; 2 | 3 | export const initUniforms = (uniforms, program) => { 4 | const gl = getContext(); 5 | 6 | const textureIndices = [ 7 | gl.TEXTURE0, 8 | gl.TEXTURE1, 9 | gl.TEXTURE2, 10 | gl.TEXTURE3, 11 | gl.TEXTURE4, 12 | gl.TEXTURE5, 13 | ]; 14 | 15 | let i = 0; 16 | 17 | Object.keys(uniforms).forEach(prop => { 18 | const current = uniforms[prop]; 19 | const location = gl.getUniformLocation(program, prop); 20 | 21 | Object.assign(current, { 22 | location, 23 | }); 24 | 25 | if (current.type === 'sampler2D') { 26 | current.textureIndex = i; 27 | current.activeTexture = textureIndices[i]; 28 | i++; 29 | } 30 | }); 31 | }; 32 | 33 | export const updateUniforms = uniforms => { 34 | const gl = getContext(); 35 | Object.keys(uniforms).forEach(key => { 36 | const uniform = uniforms[key]; 37 | 38 | switch (uniform.type) { 39 | case 'mat4': 40 | gl.uniformMatrix4fv(uniform.location, false, uniform.value); 41 | break; 42 | case 'mat3': 43 | gl.uniformMatrix3fv(uniform.location, false, uniform.value); 44 | break; 45 | case 'vec4': 46 | gl.uniform4fv(uniform.location, uniform.value); 47 | break; 48 | case 'vec3': 49 | gl.uniform3fv(uniform.location, uniform.value); 50 | break; 51 | case 'vec2': 52 | gl.uniform2fv(uniform.location, uniform.value); 53 | break; 54 | case 'float': 55 | gl.uniform1f(uniform.location, uniform.value); 56 | break; 57 | case 'sampler2D': 58 | gl.activeTexture(uniform.activeTexture); 59 | gl.bindTexture(gl.TEXTURE_2D, uniform.value); 60 | gl.uniform1i(uniform.location, uniform.textureIndex); 61 | break; 62 | default: 63 | throw new Error(`"${uniform.type}" is an unknown uniform type`); 64 | } 65 | }); 66 | }; 67 | -------------------------------------------------------------------------------- /packages/core/src/gl/vao.js: -------------------------------------------------------------------------------- 1 | import { getContext, getContextType, supports } from '../session'; 2 | import { CONTEXT } from '../constants'; 3 | 4 | class Vao { 5 | constructor() { 6 | const gl = getContext(); 7 | const { vertexArrayObject } = supports(); 8 | 9 | if (getContextType() === CONTEXT.WEBGL2) { 10 | this.vao = gl.createVertexArray(); 11 | gl.bindVertexArray(this.vao); 12 | } else if (vertexArrayObject) { 13 | this.vao = supports().vertexArrayObject.createVertexArrayOES(); 14 | vertexArrayObject.bindVertexArrayOES(this.vao); 15 | } 16 | } 17 | 18 | bind() { 19 | const gl = getContext(); 20 | const { vertexArrayObject } = supports(); 21 | 22 | if (getContextType() === CONTEXT.WEBGL2) { 23 | gl.bindVertexArray(this.vao); 24 | } else if (vertexArrayObject) { 25 | vertexArrayObject.bindVertexArrayOES(this.vao); 26 | } 27 | } 28 | 29 | unbind() { 30 | const gl = getContext(); 31 | const { vertexArrayObject } = supports(); 32 | 33 | if (getContextType() === CONTEXT.WEBGL2) { 34 | gl.bindVertexArray(null); 35 | } else if (vertexArrayObject) { 36 | vertexArrayObject.bindVertexArrayOES(null); 37 | } 38 | } 39 | 40 | destroy() { 41 | const gl = getContext(); 42 | const { vertexArrayObject } = supports(); 43 | 44 | if (getContextType() === CONTEXT.WEBGL2) { 45 | gl.deleteVertexArray(this.vao); 46 | } else if (vertexArrayObject) { 47 | vertexArrayObject.deleteVertexArrayOES(this.vao); 48 | } 49 | this.vao = null; 50 | } 51 | } 52 | 53 | export default Vao; 54 | -------------------------------------------------------------------------------- /packages/core/src/helpers/axis.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import Mesh from '../core/mesh'; 3 | import Model from '../core/model'; 4 | import { Basic } from '../shaders'; 5 | 6 | class AxisHelper extends Model { 7 | constructor(props = {}) { 8 | super(); 9 | 10 | const size = (props && props.size) || 10; 11 | const g1 = { 12 | positions: [ 13 | ...vec3.fromValues(0, 0, 0), 14 | ...vec3.fromValues(size, 0, 0), 15 | ], 16 | }; 17 | const g2 = { 18 | positions: [ 19 | ...vec3.fromValues(0, 0, 0), 20 | ...vec3.fromValues(0, size, 0), 21 | ], 22 | }; 23 | const g3 = { 24 | positions: [ 25 | ...vec3.fromValues(0, 0, 0), 26 | ...vec3.fromValues(0, 0, size), 27 | ], 28 | }; 29 | 30 | const m1 = new Basic({ 31 | color: vec3.fromValues(1, 0, 0), 32 | wireframe: true, 33 | }); 34 | const m2 = new Basic({ 35 | color: vec3.fromValues(0, 1, 0), 36 | wireframe: true, 37 | }); 38 | const m3 = new Basic({ 39 | color: vec3.fromValues(0, 0, 1), 40 | wireframe: true, 41 | }); 42 | 43 | const x = new Mesh({ geometry: g1, shader: m1 }); 44 | this.add(x); 45 | 46 | const y = new Mesh({ geometry: g2, shader: m2 }); 47 | this.add(y); 48 | 49 | const z = new Mesh({ geometry: g3, shader: m3 }); 50 | this.add(z); 51 | } 52 | } 53 | export default AxisHelper; 54 | -------------------------------------------------------------------------------- /packages/core/src/helpers/index.js: -------------------------------------------------------------------------------- 1 | import Axis from './axis'; 2 | import Normals from './normal'; 3 | 4 | export { Axis, Normals }; 5 | -------------------------------------------------------------------------------- /packages/core/src/helpers/normal.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import Mesh from '../core/mesh'; 3 | import Model from '../core/model'; 4 | import { Basic } from '../shaders'; 5 | // import { DRAW } from '../constants'; 6 | 7 | class AxisHelper extends Model { 8 | constructor(props = {}) { 9 | super(); 10 | 11 | const size = (props && props.size) || 1; 12 | const geometry = { 13 | positions: [], 14 | }; 15 | 16 | // extract geometry 17 | const sx = props.model.scale.x; 18 | const sy = props.model.scale.y; 19 | const sz = props.model.scale.z; 20 | 21 | const length = props.model.attributes.a_normal.value.length / 3; 22 | for (let i = 0; i < length; i++) { 23 | const i3 = i * 3; 24 | const v0x = sx * props.model.attributes.a_position.value[i3 + 0]; 25 | const v0y = sy * props.model.attributes.a_position.value[i3 + 1]; 26 | const v0z = sz * props.model.attributes.a_position.value[i3 + 2]; 27 | const nx = props.model.attributes.a_normal.value[i3 + 0]; 28 | const ny = props.model.attributes.a_normal.value[i3 + 1]; 29 | const nz = props.model.attributes.a_normal.value[i3 + 2]; 30 | const v1x = v0x + size * nx; 31 | const v1y = v0y + size * ny; 32 | const v1z = v0z + size * nz; 33 | geometry.positions = geometry.positions.concat([ 34 | v0x, 35 | v0y, 36 | v0z, 37 | v1x, 38 | v1y, 39 | v1z, 40 | ]); 41 | } 42 | 43 | const shader = new Basic({ 44 | color: vec3.fromValues(0, 1, 1), 45 | wireframe: true, 46 | }); 47 | const n = new Mesh({ geometry, shader }); 48 | this.add(n); 49 | 50 | this.reference = props.model; 51 | // mode = DRAW.LINES 52 | } 53 | 54 | update() { 55 | super.update(); 56 | 57 | vec3.copy(this.position.data, this.reference.position.data); 58 | vec3.copy(this.rotation.data, this.reference.rotation.data); 59 | this.lookToTarget = this.reference.lookToTarget; 60 | } 61 | } 62 | export default AxisHelper; 63 | -------------------------------------------------------------------------------- /packages/core/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Core 3 | * @module core 4 | */ 5 | import * as chunks from './shaders/chunks'; 6 | import * as utils from './utils'; 7 | import * as cameras from './cameras'; 8 | import * as shaders from './shaders'; 9 | import * as helpers from './helpers'; 10 | import * as constants from './constants'; 11 | 12 | import Renderer from './core/renderer'; 13 | import Object3 from './core/object3'; 14 | import Scene from './core/scene'; 15 | import Model from './core/model'; 16 | import Mesh from './core/mesh'; 17 | import Texture from './core/texture'; 18 | import RenderTarget from './core/rt'; 19 | import Composer from './core/composer'; 20 | import Pass from './core/pass'; 21 | import Performance from './core/performance'; 22 | 23 | export { 24 | chunks, 25 | utils, 26 | cameras, 27 | shaders, 28 | helpers, 29 | constants, 30 | Renderer, 31 | Object3, 32 | Scene, 33 | Model, 34 | Mesh, 35 | Texture, 36 | RenderTarget, 37 | Composer, 38 | Pass, 39 | Performance, 40 | }; 41 | -------------------------------------------------------------------------------- /packages/core/src/passes/basic.js: -------------------------------------------------------------------------------- 1 | const Basic = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | }, 5 | 6 | vertex: ` 7 | out vec2 v_uv; 8 | void main() { 9 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 10 | v_uv = a_uv; 11 | }`, 12 | 13 | fragment: ` 14 | in vec2 v_uv; 15 | 16 | uniform sampler2D u_input; 17 | 18 | void main() { 19 | outColor = texture(u_input, v_uv); 20 | }`, 21 | }; 22 | 23 | export default Basic; 24 | -------------------------------------------------------------------------------- /packages/core/src/passes/index.js: -------------------------------------------------------------------------------- 1 | import Basic from './basic'; 2 | 3 | export { Basic }; 4 | -------------------------------------------------------------------------------- /packages/core/src/session.js: -------------------------------------------------------------------------------- 1 | import { CONTEXT } from './constants'; 2 | 3 | const library = `lowww-${__LIBRARY__}`; 4 | const version = __VERSION__; 5 | 6 | // per session 7 | let gl = null; 8 | let contextType = null; 9 | 10 | // test context webgl and webgl2 11 | const testContext1 = document.createElement('canvas').getContext(CONTEXT.WEBGL); 12 | const testContext2 = document 13 | .createElement('canvas') 14 | .getContext(CONTEXT.WEBGL2); 15 | 16 | const extensions = { 17 | // used globally 18 | vertexArrayObject: testContext1.getExtension('OES_vertex_array_object'), 19 | 20 | // used for instancing 21 | instancedArrays: testContext1.getExtension('ANGLE_instanced_arrays'), 22 | 23 | // used for flat shading 24 | standardDerivatives: testContext1.getExtension('OES_standard_derivatives'), 25 | 26 | // depth texture 27 | depthTextures: testContext1.getExtension('WEBGL_depth_texture'), 28 | }; 29 | 30 | const setContextType = preferred => { 31 | const gl2 = testContext2 && CONTEXT.WEBGL2; 32 | const gl1 = testContext1 && CONTEXT.WEBGL; 33 | contextType = preferred || gl2 || gl1; 34 | 35 | if (contextType === CONTEXT.WEBGL2) { 36 | extensions.vertexArrayObject = true; 37 | extensions.instancedArrays = true; 38 | extensions.standardDerivatives = true; 39 | extensions.depthTexture = true; 40 | } 41 | 42 | return contextType; 43 | }; 44 | 45 | const getContextType = () => contextType; 46 | 47 | const setContext = context => { 48 | gl = context; 49 | if (getContextType() === CONTEXT.WEBGL) { 50 | extensions.vertexArrayObject = gl.getExtension( 51 | 'OES_vertex_array_object' 52 | ); 53 | extensions.instancedArrays = gl.getExtension('ANGLE_instanced_arrays'); 54 | extensions.standardDerivatives = gl.getExtension( 55 | 'OES_standard_derivatives' 56 | ); 57 | extensions.depthTextures = gl.getExtension('WEBGL_depth_texture'); 58 | } 59 | }; 60 | 61 | const getContext = () => gl; 62 | 63 | const supports = () => extensions; 64 | 65 | export { 66 | library, 67 | version, 68 | setContext, 69 | getContext, 70 | setContextType, 71 | getContextType, 72 | supports, 73 | }; 74 | -------------------------------------------------------------------------------- /packages/core/src/shaders/basic.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import { UBO, FOG, EXTENSIONS } from './chunks'; 3 | import { SHADER_BASIC, DRAW } from '../constants'; 4 | 5 | class Basic { 6 | constructor(props = {}) { 7 | const color = props.color || vec3.fromValues(1, 1, 1); 8 | 9 | const vertex = `#version 300 es 10 | ${EXTENSIONS.vertex()} 11 | 12 | in vec3 a_position; 13 | 14 | ${UBO.scene()} 15 | ${UBO.model()} 16 | 17 | void main() { 18 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 19 | } 20 | `; 21 | 22 | const fragment = `#version 300 es 23 | ${EXTENSIONS.fragment()} 24 | 25 | precision highp float; 26 | precision highp int; 27 | 28 | ${UBO.scene()} 29 | 30 | uniform vec3 u_color; 31 | 32 | out vec4 outColor; 33 | 34 | void main() { 35 | vec4 base = vec4(u_color, 1.0); 36 | 37 | ${FOG.linear()} 38 | 39 | outColor = base; 40 | } 41 | `; 42 | 43 | return Object.assign( 44 | { 45 | type: SHADER_BASIC, 46 | mode: props.wireframe === true ? DRAW.LINES : DRAW.TRIANGLES, 47 | }, 48 | { 49 | vertex, 50 | fragment, 51 | uniforms: { 52 | u_color: { 53 | type: 'vec3', 54 | value: color, 55 | }, 56 | }, 57 | } 58 | ); 59 | } 60 | } 61 | 62 | export default Basic; 63 | -------------------------------------------------------------------------------- /packages/core/src/shaders/billboard.js: -------------------------------------------------------------------------------- 1 | import { UBO, LIGHT, FOG, CLIPPING, EXTENSIONS, SHADOW } from './chunks'; 2 | import { SHADER_BILLBOARD, DRAW } from '../constants'; 3 | 4 | class Billboard { 5 | constructor(props = {}) { 6 | const vertex = `#version 300 es 7 | ${EXTENSIONS.vertex()} 8 | 9 | in vec3 a_position; 10 | in vec3 a_normal; 11 | in vec2 a_uv; 12 | 13 | ${UBO.scene()} 14 | ${UBO.model()} 15 | ${CLIPPING.vertex_pre()} 16 | ${SHADOW.vertex_pre()} 17 | 18 | out vec3 fragVertexEc; 19 | out vec2 v_uv; 20 | out vec3 v_normal; 21 | 22 | void main() { 23 | vec4 worldPosition = modelMatrix * vec4(a_position, 1.0); 24 | vec4 position = projectionMatrix * viewMatrix * worldPosition; 25 | gl_Position = position; 26 | 27 | fragVertexEc = position.xyz; // worldPosition.xyz; 28 | v_uv = a_uv; 29 | v_normal = (normalMatrix * vec4(a_normal, 1.0)).xyz; 30 | 31 | ${SHADOW.vertex()} 32 | ${CLIPPING.vertex()} 33 | } 34 | `; 35 | 36 | const fragment = `#version 300 es 37 | ${EXTENSIONS.fragment()} 38 | 39 | precision highp float; 40 | precision highp int; 41 | 42 | in vec3 fragVertexEc; 43 | in vec2 v_uv; 44 | in vec3 v_normal; 45 | 46 | ${CLIPPING.fragment_pre()} 47 | 48 | ${UBO.scene()} 49 | ${UBO.model()} 50 | ${UBO.lights()} 51 | 52 | ${SHADOW.fragment_pre()} 53 | 54 | out vec4 outColor; 55 | 56 | ${props.fragment || 57 | 'void mainImage( out vec4 fragColor, in vec2 fragCoord ) { fragColor = vec4(0.0, 1.0, 1.0, 1.0); }'} 58 | 59 | void main() { 60 | vec4 base = vec4(0.0, 0.0, 0.0, 1.0); 61 | mainImage(base, gl_FragCoord.xy); 62 | 63 | ${SHADOW.fragment()} 64 | ${LIGHT.factory()} 65 | ${FOG.linear()} 66 | ${CLIPPING.fragment()} 67 | 68 | outColor = base; 69 | } 70 | `; 71 | 72 | return Object.assign( 73 | { 74 | type: SHADER_BILLBOARD, 75 | mode: props.wireframe === true ? DRAW.LINES : DRAW.TRIANGLES, 76 | }, 77 | { 78 | vertex, 79 | fragment, 80 | uniforms: {}, 81 | } 82 | ); 83 | } 84 | } 85 | 86 | export default Billboard; 87 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/clipping.js: -------------------------------------------------------------------------------- 1 | const CLIPPING = { 2 | vertex_pre: () => { 3 | return ` 4 | out vec4 local_eyespace; 5 | out vec4 global_eyespace;`; 6 | }, 7 | 8 | vertex: () => { 9 | return ` 10 | local_eyespace = modelMatrix * vec4(a_position, 1.0); 11 | global_eyespace = viewMatrix * modelMatrix * vec4(a_position, 1.0);`; 12 | }, 13 | 14 | fragment_pre: () => { 15 | return ` 16 | in vec4 local_eyespace; 17 | in vec4 global_eyespace;`; 18 | }, 19 | 20 | fragment: () => { 21 | return ` 22 | if (localClipSettings.x > 0.0) { 23 | if(dot(local_eyespace, localClipPlane0) < 0.0) discard; 24 | if(dot(local_eyespace, localClipPlane1) < 0.0) discard; 25 | if(dot(local_eyespace, localClipPlane2) < 0.0) discard; 26 | } 27 | 28 | if (globalClipSettings.x > 0.0) { 29 | if(dot(global_eyespace, globalClipPlane0) < 0.0) discard; 30 | if(dot(global_eyespace, globalClipPlane1) < 0.0) discard; 31 | if(dot(global_eyespace, globalClipPlane2) < 0.0) discard; 32 | }`; 33 | }, 34 | }; 35 | 36 | export { CLIPPING }; 37 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/extensions.js: -------------------------------------------------------------------------------- 1 | import { getContextType } from '../../session'; 2 | import { CONTEXT } from '../../constants'; 3 | 4 | const EXTENSIONS = { 5 | vertex: () => { 6 | if (getContextType() === CONTEXT.WEBGL2) { 7 | return ''; 8 | } 9 | return ''; 10 | }, 11 | 12 | fragment: () => { 13 | if (getContextType() === CONTEXT.WEBGL2) { 14 | return ''; 15 | } 16 | return ` 17 | #extension GL_OES_standard_derivatives : enable`; 18 | }, 19 | }; 20 | 21 | export { EXTENSIONS }; 22 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/fog.js: -------------------------------------------------------------------------------- 1 | function base() { 2 | return ` 3 | float fogStart = fogSettings.y; 4 | float fogEnd = fogSettings.z; 5 | float fogDensity = fogSettings.a; 6 | 7 | float dist = 0.0; 8 | float fogFactor = 0.0; 9 | dist = gl_FragCoord.z / gl_FragCoord.w;`; 10 | } 11 | 12 | const FOG = { 13 | linear: () => { 14 | return ` 15 | if (fogSettings.x > 0.0) { 16 | ${base()} 17 | fogFactor = (fogEnd - dist) / (fogEnd - fogStart); 18 | fogFactor = clamp(fogFactor, 0.0, 1.0); 19 | base = mix(fogColor, base, fogFactor); 20 | }`; 21 | }, 22 | exponential: () => { 23 | return ` 24 | if (fogSettings.x > 0.0) { 25 | ${base()} 26 | fogFactor = 1.0 / exp(dist * fogDensity); 27 | fogFactor = clamp(fogFactor, 0.0, 1.0); 28 | base = mix(fogColor, base, fogFactor); 29 | }`; 30 | }, 31 | exponential2: () => { 32 | return ` 33 | if (fogSettings.x > 0.0) { 34 | ${base()} 35 | fogFactor = 1.0 / exp((dist * fogDensity) * (dist * fogDensity)); 36 | fogFactor = clamp(fogFactor, 0.0, 1.0); 37 | base = mix(fogColor, base, fogFactor); 38 | }`; 39 | }, 40 | }; 41 | 42 | export { FOG }; 43 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/index.js: -------------------------------------------------------------------------------- 1 | import { LIGHT } from './light'; 2 | import { FOG } from './fog'; 3 | import { UBO } from './ubo'; 4 | import { NOISE } from './noise'; 5 | import { CLIPPING } from './clipping'; 6 | import { EXTENSIONS } from './extensions'; 7 | import { SHADOW } from './shadow'; 8 | 9 | export { UBO, LIGHT, FOG, NOISE, CLIPPING, EXTENSIONS, SHADOW }; 10 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/light.js: -------------------------------------------------------------------------------- 1 | const LIGHT = { 2 | factory: () => { 3 | return ` 4 | // factory light 5 | vec3 inverseLightDirection = normalize(vec3(-0.25, -0.25, 1.0)); 6 | vec3 directionalColor = vec3(max(dot(v_normal, inverseLightDirection), 0.0)); 7 | vec3 factory = mix(vec3(0.0), directionalColor, 0.989); // light intensity 8 | base.rgb *= factory; 9 | 10 | ${LIGHT.directional()}`; 11 | }, 12 | 13 | directional: () => { 14 | return ` 15 | // vec3 dcolor = vec3(0.01); 16 | // 17 | // for (int i = 0; i < MAX_DIRECTIONAL; i++) { 18 | // vec3 inverseLightDirection = normalize(directionalLights[i].dlPosition.xyz); 19 | // vec3 light = vec3(max(dot(v_normal, inverseLightDirection), 0.0)); 20 | // vec3 directionalColor = directionalLights[i].dlColor.rgb * light; 21 | // dcolor += mix(dcolor, directionalColor, directionalLights[i].flIntensity); 22 | // } 23 | // dcolor /= float(MAX_DIRECTIONAL); 24 | // 25 | // base.rgb *= dcolor; 26 | `; 27 | }, 28 | }; 29 | 30 | export { LIGHT }; 31 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/noise.js: -------------------------------------------------------------------------------- 1 | const NOISE = () => { 2 | return ` 3 | vec3 mod289(vec3 x){return x-floor(x*(1./289.))*289.;}vec4 mod289(vec4 x){return x-floor(x*(1./289.))*289.;}vec4 permute(vec4 x){return mod289((x*34.+1.)*x);}vec4 taylorInvSqrt(vec4 r){return 1.79284-.853735*r;}vec3 fade(vec3 t){return t*t*t*(t*(t*6.-15.)+10.);}float cnoise(vec3 P){vec3 Pi0=floor(P),Pi1=Pi0+vec3(1.);Pi0=mod289(Pi0);Pi1=mod289(Pi1);vec3 Pf0=fract(P),Pf1=Pf0-vec3(1.);vec4 ix=vec4(Pi0.r,Pi1.r,Pi0.r,Pi1.r),iy=vec4(Pi0.gg,Pi1.gg),iz0=Pi0.bbbb,iz1=Pi1.bbbb,ixy=permute(permute(ix)+iy),ixy0=permute(ixy+iz0),ixy1=permute(ixy+iz1),gx0=ixy0*(1./7.),gy0=fract(floor(gx0)*(1./7.))-.5;gx0=fract(gx0);vec4 gz0=vec4(.5)-abs(gx0)-abs(gy0),sz0=step(gz0,vec4(0.));gx0-=sz0*(step(0.,gx0)-.5);gy0-=sz0*(step(0.,gy0)-.5);vec4 gx1=ixy1*(1./7.),gy1=fract(floor(gx1)*(1./7.))-.5;gx1=fract(gx1);vec4 gz1=vec4(.5)-abs(gx1)-abs(gy1),sz1=step(gz1,vec4(0.));gx1-=sz1*(step(0.,gx1)-.5);gy1-=sz1*(step(0.,gy1)-.5);vec3 g000=vec3(gx0.r,gy0.r,gz0.r),g100=vec3(gx0.g,gy0.g,gz0.g),g010=vec3(gx0.b,gy0.b,gz0.b),g110=vec3(gx0.a,gy0.a,gz0.a),g001=vec3(gx1.r,gy1.r,gz1.r),g101=vec3(gx1.g,gy1.g,gz1.g),g011=vec3(gx1.b,gy1.b,gz1.b),g111=vec3(gx1.a,gy1.a,gz1.a);vec4 norm0=taylorInvSqrt(vec4(dot(g000,g000),dot(g010,g010),dot(g100,g100),dot(g110,g110)));g000*=norm0.r;g010*=norm0.g;g100*=norm0.b;g110*=norm0.a;vec4 norm1=taylorInvSqrt(vec4(dot(g001,g001),dot(g011,g011),dot(g101,g101),dot(g111,g111)));g001*=norm1.r;g011*=norm1.g;g101*=norm1.b;g111*=norm1.a;float n000=dot(g000,Pf0),n100=dot(g100,vec3(Pf1.r,Pf0.gb)),n010=dot(g010,vec3(Pf0.r,Pf1.g,Pf0.b)),n110=dot(g110,vec3(Pf1.rg,Pf0.b)),n001=dot(g001,vec3(Pf0.rg,Pf1.b)),n101=dot(g101,vec3(Pf1.r,Pf0.g,Pf1.b)),n011=dot(g011,vec3(Pf0.r,Pf1.gb)),n111=dot(g111,Pf1);vec3 fade_xyz=fade(Pf0);vec4 n_z=mix(vec4(n000,n100,n010,n110),vec4(n001,n101,n011,n111),fade_xyz.b);vec2 n_yz=mix(n_z.rg,n_z.ba,fade_xyz.g);float n_xyz=mix(n_yz.r,n_yz.g,fade_xyz.r);return 2.2*n_xyz;}float pnoise(vec3 P,vec3 rep){vec3 Pi0=mod(floor(P),rep),Pi1=mod(Pi0+vec3(1.),rep);Pi0=mod289(Pi0);Pi1=mod289(Pi1);vec3 Pf0=fract(P),Pf1=Pf0-vec3(1.);vec4 ix=vec4(Pi0.r,Pi1.r,Pi0.r,Pi1.r),iy=vec4(Pi0.gg,Pi1.gg),iz0=Pi0.bbbb,iz1=Pi1.bbbb,ixy=permute(permute(ix)+iy),ixy0=permute(ixy+iz0),ixy1=permute(ixy+iz1),gx0=ixy0*(1./7.),gy0=fract(floor(gx0)*(1./7.))-.5;gx0=fract(gx0);vec4 gz0=vec4(.5)-abs(gx0)-abs(gy0),sz0=step(gz0,vec4(0.));gx0-=sz0*(step(0.,gx0)-.5);gy0-=sz0*(step(0.,gy0)-.5);vec4 gx1=ixy1*(1./7.),gy1=fract(floor(gx1)*(1./7.))-.5;gx1=fract(gx1);vec4 gz1=vec4(.5)-abs(gx1)-abs(gy1),sz1=step(gz1,vec4(0.));gx1-=sz1*(step(0.,gx1)-.5);gy1-=sz1*(step(0.,gy1)-.5);vec3 g000=vec3(gx0.r,gy0.r,gz0.r),g100=vec3(gx0.g,gy0.g,gz0.g),g010=vec3(gx0.b,gy0.b,gz0.b),g110=vec3(gx0.a,gy0.a,gz0.a),g001=vec3(gx1.r,gy1.r,gz1.r),g101=vec3(gx1.g,gy1.g,gz1.g),g011=vec3(gx1.b,gy1.b,gz1.b),g111=vec3(gx1.a,gy1.a,gz1.a);vec4 norm0=taylorInvSqrt(vec4(dot(g000,g000),dot(g010,g010),dot(g100,g100),dot(g110,g110)));g000*=norm0.r;g010*=norm0.g;g100*=norm0.b;g110*=norm0.a;vec4 norm1=taylorInvSqrt(vec4(dot(g001,g001),dot(g011,g011),dot(g101,g101),dot(g111,g111)));g001*=norm1.r;g011*=norm1.g;g101*=norm1.b;g111*=norm1.a;float n000=dot(g000,Pf0),n100=dot(g100,vec3(Pf1.r,Pf0.gb)),n010=dot(g010,vec3(Pf0.r,Pf1.g,Pf0.b)),n110=dot(g110,vec3(Pf1.rg,Pf0.b)),n001=dot(g001,vec3(Pf0.rg,Pf1.b)),n101=dot(g101,vec3(Pf1.r,Pf0.g,Pf1.b)),n011=dot(g011,vec3(Pf0.r,Pf1.gb)),n111=dot(g111,Pf1);vec3 fade_xyz=fade(Pf0);vec4 n_z=mix(vec4(n000,n100,n010,n110),vec4(n001,n101,n011,n111),fade_xyz.b);vec2 n_yz=mix(n_z.rg,n_z.ba,fade_xyz.g);float n_xyz=mix(n_yz.r,n_yz.g,fade_xyz.r);return 2.2*n_xyz;} 4 | `; 5 | }; 6 | 7 | export { NOISE }; 8 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/shadow.js: -------------------------------------------------------------------------------- 1 | function hard() { 2 | return ` 3 | float hardShadow1(sampler2D shadowMap) { 4 | vec4 shadowCoord = vShadowCoord / vShadowCoord.w; 5 | vec2 uv = shadowCoord.xy; 6 | float shadow = texture(shadowMap, uv).r; 7 | 8 | float visibility = 1.0; 9 | float shadowAmount = 0.5; 10 | 11 | float cosTheta = clamp(dot(v_normal, vShadowCoord.xyz), 0.0, 1.0); 12 | float bias = 0.00005 * tan(acos(cosTheta)); // cosTheta is dot( n,l ), clamped between 0 and 1 13 | bias = clamp(bias, 0.0, 0.001); 14 | 15 | if (shadow < shadowCoord.z - bias){ 16 | visibility = shadowAmount; 17 | } 18 | return visibility; 19 | } 20 | 21 | float hardShadow2(sampler2D shadowMap) { 22 | vec4 shadowCoord = vShadowCoord / vShadowCoord.w; 23 | vec2 uv = shadowCoord.xy; 24 | 25 | float lightDepth1 = texture(shadowMap, uv).r; 26 | float lightDepth2 = clamp(shadowCoord.z, 0.0, 1.0); 27 | float bias = 0.0001; 28 | 29 | return step(lightDepth2, lightDepth1+bias); 30 | } 31 | 32 | float hardShadow3(sampler2D shadowMap) { 33 | vec4 shadowCoord = vShadowCoord / vShadowCoord.w; 34 | vec2 uv = shadowCoord.xy; 35 | 36 | float visibility = 1.0; 37 | float shadowAmount = 0.5; 38 | float bias = 0.00005; 39 | 40 | vec2 poissonDisk[16]; 41 | poissonDisk[0] = vec2(-0.94201624, -0.39906216); 42 | poissonDisk[1] = vec2(0.94558609, -0.76890725); 43 | poissonDisk[2] = vec2(-0.094184101, -0.92938870); 44 | poissonDisk[3] = vec2(0.34495938, 0.29387760); 45 | poissonDisk[4] = vec2(-0.91588581, 0.45771432); 46 | poissonDisk[5] = vec2(-0.81544232, -0.87912464); 47 | poissonDisk[6] = vec2(-0.38277543, 0.27676845); 48 | poissonDisk[7] = vec2(0.97484398, 0.75648379); 49 | poissonDisk[8] = vec2(0.44323325, -0.97511554); 50 | poissonDisk[9] = vec2(0.53742981, -0.47373420); 51 | poissonDisk[10] = vec2(-0.26496911, -0.41893023); 52 | poissonDisk[11] = vec2(0.79197514, 0.19090188); 53 | poissonDisk[12] = vec2(-0.24188840, 0.99706507); 54 | poissonDisk[13] = vec2(-0.81409955, 0.91437590); 55 | poissonDisk[14] = vec2(0.19984126, 0.78641367); 56 | poissonDisk[15] = vec2(0.14383161, -0.14100790); 57 | 58 | for (int i=0;i<16;i++) { 59 | if ( texture(shadowMap, uv + poissonDisk[i]/700.0).r < shadowCoord.z-bias ){ 60 | visibility -= 0.02; 61 | } 62 | } 63 | 64 | return visibility; 65 | } 66 | 67 | `; 68 | } 69 | 70 | const SHADOW = { 71 | vertex_pre: () => { 72 | return ` 73 | uniform mat4 shadowMatrix; 74 | out vec4 vShadowCoord;`; 75 | }, 76 | 77 | vertex: () => { 78 | return ` 79 | vShadowCoord = shadowMatrix * modelMatrix * vec4(a_position, 1.0);`; 80 | }, 81 | 82 | fragment_pre: () => { 83 | return ` 84 | uniform sampler2D shadowMap; 85 | in vec4 vShadowCoord; 86 | 87 | ${hard()}`; 88 | }, 89 | 90 | fragment: () => { 91 | return ` 92 | // shadows 93 | float shadow = 1.0; 94 | 95 | // OPTION 1 96 | shadow = hardShadow1(shadowMap); 97 | 98 | base *= shadow; 99 | `; 100 | }, 101 | }; 102 | 103 | export { SHADOW }; 104 | -------------------------------------------------------------------------------- /packages/core/src/shaders/chunks/ubo.js: -------------------------------------------------------------------------------- 1 | import { CONTEXT, MAX_DIRECTIONAL } from '../../constants'; 2 | import { getContextType } from '../../session'; 3 | 4 | const UBO = { 5 | scene: () => { 6 | if (getContextType() === CONTEXT.WEBGL2) { 7 | return ` 8 | uniform perScene { 9 | mat4 projectionMatrix; 10 | mat4 viewMatrix; 11 | vec4 fogSettings; 12 | vec4 fogColor; 13 | float iGlobalTime; 14 | vec4 globalClipSettings; 15 | vec4 globalClipPlane0; 16 | vec4 globalClipPlane1; 17 | vec4 globalClipPlane2; 18 | };`; 19 | } 20 | 21 | return ` 22 | uniform mat4 projectionMatrix; 23 | uniform mat4 viewMatrix; 24 | uniform vec4 fogSettings; 25 | uniform vec4 fogColor; 26 | uniform float iGlobalTime; 27 | uniform vec4 globalClipSettings; 28 | uniform vec4 globalClipPlane0; 29 | uniform vec4 globalClipPlane1; 30 | uniform vec4 globalClipPlane2;`; 31 | }, 32 | 33 | model: () => { 34 | if (getContextType() === CONTEXT.WEBGL2) { 35 | return ` 36 | uniform perModel { 37 | mat4 modelMatrix; 38 | mat4 normalMatrix; 39 | vec4 localClipSettings; 40 | vec4 localClipPlane0; 41 | vec4 localClipPlane1; 42 | vec4 localClipPlane2; 43 | };`; 44 | } 45 | return ` 46 | uniform mat4 modelMatrix; 47 | uniform mat4 normalMatrix; 48 | uniform vec4 localClipSettings; 49 | uniform vec4 localClipPlane0; 50 | uniform vec4 localClipPlane1; 51 | uniform vec4 localClipPlane2;`; 52 | }, 53 | 54 | lights: () => { 55 | if (getContextType() === CONTEXT.WEBGL2) { 56 | return ` 57 | #define MAX_DIRECTIONAL ${MAX_DIRECTIONAL} 58 | 59 | struct Directional { 60 | vec4 dlPosition; 61 | vec4 dlColor; 62 | float flIntensity; 63 | }; 64 | 65 | uniform directional { 66 | Directional directionalLights[MAX_DIRECTIONAL]; 67 | };`; 68 | } 69 | 70 | return ` 71 | #define MAX_DIRECTIONAL ${MAX_DIRECTIONAL} 72 | 73 | struct Directional { 74 | vec4 dlPosition; 75 | vec4 dlColor; 76 | float flIntensity; 77 | }; 78 | 79 | uniform Directional directionalLights[MAX_DIRECTIONAL];`; 80 | }, 81 | }; 82 | 83 | export { UBO }; 84 | -------------------------------------------------------------------------------- /packages/core/src/shaders/default.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import Texture from '../core/texture'; 3 | import { UBO, LIGHT, FOG, CLIPPING, EXTENSIONS, SHADOW } from './chunks'; 4 | import { SHADER_DEFAULT, DRAW } from '../constants'; 5 | 6 | class Default { 7 | constructor(props = {}) { 8 | const color = props.color || vec3.fromValues(1, 1, 1); 9 | this.map = new Texture({ transparent: true }); 10 | 11 | // map: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/620678/red.jpg'. 12 | if (props.map) { 13 | this.map.fromImage(props.map); 14 | } 15 | 16 | // texture: new Texture() 17 | if (props.texture) { 18 | this.map = props.texture; 19 | } 20 | 21 | const vertex = `#version 300 es 22 | ${EXTENSIONS.vertex()} 23 | 24 | in vec3 a_position; 25 | in vec3 a_normal; 26 | in vec2 a_uv; 27 | 28 | ${UBO.scene()} 29 | ${UBO.model()} 30 | ${CLIPPING.vertex_pre()} 31 | ${SHADOW.vertex_pre()} 32 | 33 | out vec3 fragVertexEc; 34 | out vec2 v_uv; 35 | out vec3 v_normal; 36 | 37 | void main() { 38 | vec4 worldPosition = modelMatrix * vec4(a_position, 1.0); 39 | vec4 position = projectionMatrix * viewMatrix * worldPosition; 40 | gl_Position = position; 41 | 42 | fragVertexEc = position.xyz; // worldPosition.xyz; 43 | v_uv = a_uv; 44 | v_normal = (normalMatrix * vec4(a_normal, 1.0)).xyz; 45 | 46 | ${SHADOW.vertex()} 47 | ${CLIPPING.vertex()} 48 | } 49 | `; 50 | 51 | const fragment = `#version 300 es 52 | ${EXTENSIONS.fragment()} 53 | 54 | precision highp float; 55 | precision highp int; 56 | 57 | in vec3 fragVertexEc; 58 | in vec2 v_uv; 59 | in vec3 v_normal; 60 | 61 | ${CLIPPING.fragment_pre()} 62 | 63 | ${UBO.scene()} 64 | ${UBO.model()} 65 | ${UBO.lights()} 66 | 67 | uniform sampler2D u_map; 68 | uniform vec3 u_color; 69 | 70 | ${SHADOW.fragment_pre()} 71 | 72 | out vec4 outColor; 73 | 74 | void main() { 75 | vec3 v_normal = normalize(cross(dFdx(fragVertexEc), dFdy(fragVertexEc))); 76 | 77 | vec4 base = vec4(0.0, 0.0, 0.0, 1.0); 78 | base += vec4(u_color, 1.0); 79 | base *= texture(u_map, v_uv); 80 | 81 | ${SHADOW.fragment()} 82 | ${LIGHT.factory()} 83 | ${FOG.linear()} 84 | ${CLIPPING.fragment()} 85 | 86 | outColor = base; 87 | } 88 | `; 89 | 90 | return Object.assign( 91 | { 92 | type: SHADER_DEFAULT, 93 | mode: props.wireframe === true ? DRAW.LINES : DRAW.TRIANGLES, 94 | }, 95 | { 96 | vertex, 97 | fragment, 98 | uniforms: { 99 | u_map: { 100 | type: 'sampler2D', 101 | value: this.map.texture, 102 | }, 103 | 104 | u_color: { 105 | type: 'vec3', 106 | value: color, 107 | }, 108 | }, 109 | } 110 | ); 111 | } 112 | } 113 | 114 | export default Default; 115 | -------------------------------------------------------------------------------- /packages/core/src/shaders/index.js: -------------------------------------------------------------------------------- 1 | import Basic from './basic'; 2 | import Default from './default'; 3 | import Billboard from './billboard'; 4 | import Sem from './sem'; 5 | 6 | export { Basic, Default, Billboard, Sem }; 7 | -------------------------------------------------------------------------------- /packages/core/src/shaders/sem.js: -------------------------------------------------------------------------------- 1 | import Texture from '../core/texture'; 2 | import { UBO, FOG, CLIPPING, EXTENSIONS } from './chunks'; 3 | import { SHADER_SEM } from '../constants'; 4 | 5 | class Sem { 6 | constructor(props = {}) { 7 | this.map = new Texture({ transparent: true }); 8 | 9 | if (props.map) { 10 | this.map.fromImage(props.map); 11 | } 12 | 13 | // texture: new Texture() 14 | if (props.texture) { 15 | this.map = props.texture; 16 | } 17 | 18 | const vertex = `#version 300 es 19 | ${EXTENSIONS.vertex()} 20 | 21 | in vec3 a_position; 22 | in vec3 a_normal; 23 | in vec2 a_uv; 24 | 25 | ${UBO.scene()} 26 | ${UBO.model()} 27 | ${CLIPPING.vertex_pre()} 28 | 29 | out vec2 v_uv; 30 | 31 | void main() { 32 | vec4 position = viewMatrix * modelMatrix * vec4(a_position, 1.0); 33 | gl_Position = projectionMatrix * position; 34 | 35 | vec3 v_e = vec3(position); 36 | vec3 v_n = mat3(viewMatrix * modelMatrix) * a_normal; 37 | vec3 r = reflect(normalize(v_e), normalize(v_n)); 38 | float m = 2.0 * sqrt(pow(r.x, 2.0) + pow(r.y, 2.0) + pow(r.z + 1.0, 2.0)); 39 | v_uv = r.xy / m + 0.5; 40 | 41 | ${CLIPPING.vertex()} 42 | } 43 | `; 44 | 45 | const fragment = `#version 300 es 46 | ${EXTENSIONS.fragment()} 47 | 48 | precision highp float; 49 | precision highp int; 50 | 51 | in vec2 v_uv; 52 | 53 | ${CLIPPING.fragment_pre()} 54 | 55 | ${UBO.scene()} 56 | ${UBO.model()} 57 | ${UBO.lights()} 58 | 59 | uniform sampler2D u_map; 60 | 61 | out vec4 outColor; 62 | 63 | void main() { 64 | vec4 base = vec4(0.0, 0.0, 0.0, 1.0); 65 | 66 | base += texture(u_map, v_uv); 67 | 68 | ${FOG.linear()} 69 | ${CLIPPING.fragment()} 70 | 71 | outColor = base; 72 | } 73 | `; 74 | 75 | return Object.assign( 76 | { 77 | type: SHADER_SEM, 78 | }, 79 | { 80 | vertex, 81 | fragment, 82 | uniforms: { 83 | u_map: { 84 | type: 'sampler2D', 85 | value: this.map.texture, 86 | }, 87 | }, 88 | } 89 | ); 90 | } 91 | } 92 | 93 | export default Sem; 94 | -------------------------------------------------------------------------------- /packages/core/src/utils/color.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | 3 | // pvt 4 | function normalize(array) { 5 | return vec3.fromValues(array[0] / 255, array[1] / 255, array[2] / 255); 6 | } 7 | 8 | export function hexIntToRgb(hex) { 9 | const r = hex >> 16; 10 | const g = (hex >> 8) & 0xff; // eslint-disable-line 11 | const b = hex & 0xff; 12 | return vec3.fromValues(r, g, b); 13 | } 14 | 15 | export function hexStringToRgb(hex) { 16 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 17 | return result 18 | ? vec3.fromValues( 19 | parseInt(result[1], 16), 20 | parseInt(result[2], 16), 21 | parseInt(result[3], 16) 22 | ) 23 | : null; 24 | } 25 | 26 | export function componentToHex(c) { 27 | const hex = c.toString(16); 28 | return hex.length === 1 ? `0${hex}` : hex; 29 | } 30 | 31 | export function rgbToHex(r, g, b) { 32 | const hexR = componentToHex(r); 33 | const hexG = componentToHex(g); 34 | const hexB = componentToHex(b); 35 | return `#${hexR}${hexG}${hexB}`; 36 | } 37 | 38 | export function convert(hex) { 39 | const color = vec3.create(); 40 | const rgb = 41 | typeof hex === 'number' ? hexIntToRgb(hex) : hexStringToRgb(hex); 42 | vec3.copy(color, normalize(rgb)); 43 | return color; 44 | } 45 | -------------------------------------------------------------------------------- /packages/core/src/utils/dom.js: -------------------------------------------------------------------------------- 1 | export function resize(domElement, width, height, ratio) { 2 | domElement.width = width * ratio; 3 | domElement.height = height * ratio; 4 | domElement.style.width = `${width}px`; 5 | domElement.style.height = `${height}px`; 6 | } 7 | 8 | export function unsupported() { 9 | const div = document.createElement('div'); 10 | div.innerHTML = 11 | 'Your browser doesn\'t support WebGL.
Get WebGL'; 12 | div.style.display = 'table'; 13 | div.style.margin = '20px auto 0 auto'; 14 | div.style.border = '1px solid #333'; 15 | div.style.backgroundColor = 'rgba(255, 255, 255, 0.1)'; 16 | div.style.borderRadius = '4px'; 17 | div.style.padding = '10px'; 18 | div.style.fontFamily = 'monospace'; 19 | div.style.fontSize = '12px'; 20 | div.style.textAlign = 'center'; 21 | return div; 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/src/utils/index.js: -------------------------------------------------------------------------------- 1 | import * as color from './color'; 2 | import * as math from './math'; 3 | import glsl3to1 from './glsl-parser'; 4 | 5 | export { color, math, glsl3to1 }; 6 | -------------------------------------------------------------------------------- /packages/core/src/utils/math.js: -------------------------------------------------------------------------------- 1 | export function randomRange(min, max) { 2 | return Math.random() * (max - min) + min; 3 | } 4 | 5 | export function mod(m, n) { 6 | return ((m % n) + n) % n; 7 | } 8 | -------------------------------------------------------------------------------- /packages/geometries/README.md: -------------------------------------------------------------------------------- 1 | # lowww-geometries 2 | Adds geometries for the [lowww](https://github.com/andrevenancio/lowww) engine. 3 | 4 | ## Installation 5 | `npm install --save lowww-geometries` 6 | 7 | 8 | ## Usage 9 | ```javascript 10 | import { Renderer, Scene, cameras, Mesh } from 'lowww-core'; 11 | import { Icosahedron } from 'lowww-geometries'; 12 | 13 | let renderer; 14 | let camera; 15 | let scene; 16 | let mesh; 17 | 18 | init(); 19 | update(); 20 | 21 | const init = () => { 22 | renderer = new Renderer(); 23 | renderer.setSize(400, 300); 24 | document.body.appendChild(renderer.domElement); 25 | 26 | camera = new cameras.Perspective(); 27 | camera.position.set(0, 0, 500); 28 | 29 | scene = new Scene(); 30 | 31 | const geometry = new Icosahedron({ radius: 10, detail: 1 }); 32 | mesh = new Mesh({ geometry }); 33 | scene.add(mesh); 34 | }; 35 | 36 | const update = () => { 37 | renderer.render(scene, camera); 38 | requestAnimationFrame(update.bind(this)); 39 | }; 40 | ``` 41 | 42 | 43 | ## License 44 | MIT 45 | -------------------------------------------------------------------------------- /packages/geometries/package.json: -------------------------------------------------------------------------------- 1 | {"name":"lowww-geometries","description":"WebGL 2 Engine extension","author":"Andre Venancio (info@andrevenancio.com)","version":"1.1.5","main":"src/index.js","module":"build/geometries.module.js","repository":"git@github.com:andrevenancio/lowww.git","scripts":{"test":"echo 'Error: no test specified' && exit 0"},"devDependencies":{},"dependencies":{"gl-matrix":"^2.5.1"}} -------------------------------------------------------------------------------- /packages/geometries/src/hexahedron/index.js: -------------------------------------------------------------------------------- 1 | import Polyhedra from '../polyhedra'; 2 | 3 | class Hexahedron extends Polyhedra { 4 | constructor(props) { 5 | const settings = Object.assign( 6 | {}, 7 | { 8 | radius: 0.5, 9 | detail: 0, 10 | }, 11 | props 12 | ); 13 | 14 | const r = settings.radius * 2; 15 | 16 | const positions = [ 17 | // Front face 18 | -1.0, 19 | -1.0, 20 | 1.0, 21 | 1.0, 22 | -1.0, 23 | 1.0, 24 | 1.0, 25 | 1.0, 26 | 1.0, 27 | -1.0, 28 | 1.0, 29 | 1.0, 30 | // Back face 31 | -1.0, 32 | -1.0, 33 | -1.0, 34 | -1.0, 35 | 1.0, 36 | -1.0, 37 | 1.0, 38 | 1.0, 39 | -1.0, 40 | 1.0, 41 | -1.0, 42 | -1.0, 43 | // Top face 44 | -1.0, 45 | 1.0, 46 | -1.0, 47 | -1.0, 48 | 1.0, 49 | 1.0, 50 | 1.0, 51 | 1.0, 52 | 1.0, 53 | 1.0, 54 | 1.0, 55 | -1.0, 56 | // Bottom face 57 | -1.0, 58 | -1.0, 59 | -1.0, 60 | 1.0, 61 | -1.0, 62 | -1.0, 63 | 1.0, 64 | -1.0, 65 | 1.0, 66 | -1.0, 67 | -1.0, 68 | 1.0, 69 | // Right face 70 | 1.0, 71 | -1.0, 72 | -1.0, 73 | 1.0, 74 | 1.0, 75 | -1.0, 76 | 1.0, 77 | 1.0, 78 | 1.0, 79 | 1.0, 80 | -1.0, 81 | 1.0, 82 | // Left face 83 | -1.0, 84 | -1.0, 85 | -1.0, 86 | -1.0, 87 | -1.0, 88 | 1.0, 89 | -1.0, 90 | 1.0, 91 | 1.0, 92 | -1.0, 93 | 1.0, 94 | -1.0, 95 | ]; 96 | 97 | for (let i = 0; i < positions.length; i += 3) { 98 | positions[i + 0] *= r; 99 | positions[i + 1] *= r; 100 | positions[i + 2] *= r; 101 | } 102 | 103 | const indices = [ 104 | // Front face 105 | 0, 106 | 1, 107 | 2, 108 | 0, 109 | 2, 110 | 3, 111 | // Back face 112 | 4, 113 | 5, 114 | 6, 115 | 4, 116 | 6, 117 | 7, 118 | // Top face 119 | 8, 120 | 9, 121 | 10, 122 | 8, 123 | 10, 124 | 11, 125 | // Bottom face 126 | 12, 127 | 13, 128 | 14, 129 | 12, 130 | 14, 131 | 15, 132 | // Right face 133 | 16, 134 | 17, 135 | 18, 136 | 16, 137 | 18, 138 | 19, 139 | // Left face 140 | 20, 141 | 21, 142 | 22, 143 | 20, 144 | 22, 145 | 23, 146 | ]; 147 | 148 | super(positions, indices, r, settings.detail); 149 | 150 | return this.geometry; 151 | } 152 | } 153 | 154 | export default Hexahedron; 155 | -------------------------------------------------------------------------------- /packages/geometries/src/icosahedron/index.js: -------------------------------------------------------------------------------- 1 | import Polyhedra from '../polyhedra'; 2 | 3 | class Icosahedron extends Polyhedra { 4 | constructor(props) { 5 | const settings = Object.assign( 6 | {}, 7 | { 8 | radius: 0.5, 9 | detail: 0, 10 | }, 11 | props 12 | ); 13 | 14 | const t = 0.5 + Math.sqrt(5) / 2; 15 | const r = settings.radius * 2; 16 | 17 | const positions = [ 18 | -1, 19 | +t, 20 | 0, 21 | +1, 22 | +t, 23 | 0, 24 | -1, 25 | -t, 26 | 0, 27 | +1, 28 | -t, 29 | 0, 30 | 0, 31 | -1, 32 | +t, 33 | 0, 34 | +1, 35 | +t, 36 | 0, 37 | -1, 38 | -t, 39 | 0, 40 | +1, 41 | -t, 42 | +t, 43 | 0, 44 | -1, 45 | +t, 46 | 0, 47 | +1, 48 | -t, 49 | 0, 50 | -1, 51 | -t, 52 | 0, 53 | +1, 54 | ]; 55 | 56 | const indices = [ 57 | 0, 58 | 11, 59 | 5, 60 | 0, 61 | 5, 62 | 1, 63 | 0, 64 | 1, 65 | 7, 66 | 0, 67 | 7, 68 | 10, 69 | 0, 70 | 10, 71 | 11, 72 | 1, 73 | 5, 74 | 9, 75 | 5, 76 | 11, 77 | 4, 78 | 11, 79 | 10, 80 | 2, 81 | 10, 82 | 7, 83 | 6, 84 | 7, 85 | 1, 86 | 8, 87 | 3, 88 | 9, 89 | 4, 90 | 3, 91 | 4, 92 | 2, 93 | 3, 94 | 2, 95 | 6, 96 | 3, 97 | 6, 98 | 8, 99 | 3, 100 | 8, 101 | 9, 102 | 4, 103 | 9, 104 | 5, 105 | 2, 106 | 4, 107 | 11, 108 | 6, 109 | 2, 110 | 10, 111 | 8, 112 | 6, 113 | 7, 114 | 9, 115 | 8, 116 | 1, 117 | ]; 118 | 119 | super(positions, indices, r, settings.detail); 120 | 121 | return this.geometry; 122 | } 123 | } 124 | 125 | export default Icosahedron; 126 | -------------------------------------------------------------------------------- /packages/geometries/src/index.js: -------------------------------------------------------------------------------- 1 | import * as utils from './utils'; 2 | 3 | import Tetrahedron from './tetrahedron'; 4 | import Hexahedron from './hexahedron'; 5 | import Octahedron from './octahedron'; 6 | import Dodecahedron from './dodecahedron'; 7 | import Icosahedron from './icosahedron'; 8 | 9 | import Plane from './plane'; 10 | import Box from './box'; 11 | import Sphere from './sphere'; 12 | import Torus from './torus'; 13 | import TorusKnot from './torusknot'; 14 | import Prism from './prism'; 15 | 16 | export { 17 | utils, 18 | /* PLATONIC SOLIDS */ 19 | Tetrahedron, 20 | Hexahedron, 21 | Octahedron, 22 | Dodecahedron, 23 | Icosahedron, 24 | /* OTHER */ 25 | Plane, 26 | Box, 27 | Sphere, 28 | Torus, 29 | TorusKnot, 30 | Prism, 31 | }; 32 | -------------------------------------------------------------------------------- /packages/geometries/src/octahedron/index.js: -------------------------------------------------------------------------------- 1 | import Polyhedra from '../polyhedra'; 2 | 3 | class Octahedron extends Polyhedra { 4 | constructor(props) { 5 | const settings = Object.assign( 6 | {}, 7 | { 8 | radius: 0.5, 9 | detail: 0, 10 | }, 11 | props 12 | ); 13 | 14 | const positions = [ 15 | 1, 16 | 0, 17 | 0, 18 | -1, 19 | 0, 20 | 0, 21 | 0, 22 | 1, 23 | 0, 24 | 0, 25 | -1, 26 | 0, 27 | 0, 28 | 0, 29 | 1, 30 | 0, 31 | 0, 32 | -1, 33 | ]; 34 | 35 | const indices = [ 36 | 0, 37 | 2, 38 | 4, 39 | 0, 40 | 4, 41 | 3, 42 | 0, 43 | 3, 44 | 5, 45 | 0, 46 | 5, 47 | 2, 48 | 1, 49 | 2, 50 | 5, 51 | 1, 52 | 5, 53 | 3, 54 | 1, 55 | 3, 56 | 4, 57 | 1, 58 | 4, 59 | 2, 60 | ]; 61 | 62 | super(positions, indices, settings.radius * 2, settings.detail); 63 | 64 | return this.geometry; 65 | } 66 | } 67 | 68 | export default Octahedron; 69 | -------------------------------------------------------------------------------- /packages/geometries/src/prism/index.js: -------------------------------------------------------------------------------- 1 | class Prism { 2 | constructor(props) { 3 | const settings = Object.assign( 4 | {}, 5 | { 6 | width: 1, 7 | height: 1, 8 | depth: 1, 9 | }, 10 | props 11 | ); 12 | 13 | const positions = [ 14 | // Front face 15 | -0.5, 16 | -0.5, 17 | +0.5, // 0 18 | +0.5, 19 | -0.5, 20 | +0.5, // 1 21 | +0.5, 22 | +0.5, 23 | -0.5, // 2 24 | -0.5, 25 | +0.5, 26 | -0.5, // 3 27 | 28 | // back 29 | +0.5, 30 | -0.5, 31 | -0.5, // 4 32 | -0.5, 33 | -0.5, 34 | -0.5, // 5 35 | ]; 36 | 37 | for (let i = 0; i < positions.length; i += 3) { 38 | positions[i + 0] *= settings.width; 39 | positions[i + 1] *= settings.height; 40 | positions[i + 2] *= settings.depth; 41 | } 42 | 43 | const indices = [ 44 | // Front face 45 | 0, 46 | 1, 47 | 2, 48 | 0, 49 | 2, 50 | 3, 51 | // Back face 52 | 4, 53 | 3, 54 | 2, 55 | 4, 56 | 5, 57 | 3, 58 | // bottom 59 | 1, 60 | 0, 61 | 5, 62 | 1, 63 | 5, 64 | 4, 65 | // left 66 | 5, 67 | 0, 68 | 3, 69 | // right 70 | 1, 71 | 4, 72 | 2, 73 | ]; 74 | 75 | return { 76 | positions, 77 | indices, 78 | }; 79 | } 80 | } 81 | 82 | export default Prism; 83 | -------------------------------------------------------------------------------- /packages/geometries/src/sphere/index.js: -------------------------------------------------------------------------------- 1 | import { mat4, vec3 } from 'gl-matrix'; 2 | 3 | const matRotY = mat4.create(); 4 | const matRotZ = mat4.create(); 5 | const up = vec3.fromValues(0, 1, 0); 6 | const tmpVec3 = vec3.create(); 7 | 8 | class Sphere { 9 | constructor(props) { 10 | const settings = Object.assign( 11 | {}, 12 | { 13 | radius: 0.5, 14 | segments: 8, 15 | }, 16 | props 17 | ); 18 | 19 | const positions = []; 20 | const indices = []; 21 | const normals = []; 22 | const uvs = []; 23 | 24 | const heightSegments = 2 + settings.segments; 25 | const widthSegments = 2 * heightSegments; 26 | 27 | for (let zStep = 0; zStep <= heightSegments; zStep++) { 28 | const v = zStep / heightSegments; 29 | const angleZ = v * Math.PI; 30 | 31 | for (let yStep = 0; yStep <= widthSegments; yStep++) { 32 | const u = yStep / widthSegments; 33 | const angleY = u * Math.PI * 2; 34 | 35 | mat4.identity(matRotZ); 36 | mat4.rotateZ(matRotZ, matRotZ, -angleZ); 37 | 38 | mat4.identity(matRotY); 39 | mat4.rotateY(matRotY, matRotY, angleY); 40 | 41 | vec3.transformMat4(tmpVec3, up, matRotZ); 42 | vec3.transformMat4(tmpVec3, tmpVec3, matRotY); 43 | 44 | vec3.scale(tmpVec3, tmpVec3, -(settings.radius * 2)); 45 | positions.push(...tmpVec3); 46 | 47 | vec3.normalize(tmpVec3, tmpVec3); 48 | normals.push(...tmpVec3); 49 | 50 | uvs.push(u, v); 51 | } 52 | 53 | if (zStep > 0) { 54 | const vertices = positions.length / 3; 55 | let firstIndex = vertices - 2 * (widthSegments + 1); 56 | for ( 57 | ; 58 | firstIndex + widthSegments + 2 < vertices; 59 | firstIndex++ 60 | ) { 61 | indices.push( 62 | firstIndex, 63 | firstIndex + 1, 64 | firstIndex + widthSegments + 1 65 | ); 66 | indices.push( 67 | firstIndex + widthSegments + 1, 68 | firstIndex + 1, 69 | firstIndex + widthSegments + 2 70 | ); 71 | } 72 | } 73 | } 74 | 75 | return { 76 | positions, 77 | indices, 78 | normals, 79 | uvs, 80 | }; 81 | } 82 | } 83 | 84 | export default Sphere; 85 | -------------------------------------------------------------------------------- /packages/geometries/src/tetrahedron/index.js: -------------------------------------------------------------------------------- 1 | import Polyhedra from '../polyhedra'; 2 | 3 | class Tetrahedron extends Polyhedra { 4 | constructor(props) { 5 | const settings = Object.assign( 6 | {}, 7 | { 8 | radius: 0.5, 9 | detail: 0, 10 | }, 11 | props 12 | ); 13 | 14 | const positions = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1]; 15 | 16 | const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1]; 17 | 18 | super(positions, indices, settings.radius * 2, settings.detail); 19 | 20 | return this.geometry; 21 | } 22 | } 23 | 24 | export default Tetrahedron; 25 | -------------------------------------------------------------------------------- /packages/geometries/src/torus/index.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | 3 | class Torus { 4 | constructor(props) { 5 | const settings = Object.assign( 6 | {}, 7 | { 8 | radius: 1, 9 | tube: 0.375, 10 | tubularSegments: 16, 11 | radialSegments: 8, 12 | arc: Math.PI * 2, 13 | }, 14 | props 15 | ); 16 | 17 | const positions = []; 18 | const indices = []; 19 | const normals = []; 20 | const uvs = []; 21 | 22 | const center = vec3.create(); 23 | const vertex = vec3.create(); 24 | const normal = vec3.create(); 25 | 26 | for (let j = 0; j <= settings.radialSegments; j++) { 27 | for (let i = 0; i <= settings.tubularSegments; i++) { 28 | const u = (i / settings.tubularSegments) * settings.arc; 29 | const v = (j / settings.radialSegments) * Math.PI * 2; 30 | 31 | vertex[0] = 32 | (settings.radius + settings.tube * Math.cos(v)) * 33 | Math.cos(u); 34 | vertex[1] = 35 | (settings.radius + settings.tube * Math.cos(v)) * 36 | Math.sin(u); 37 | vertex[2] = settings.tube * Math.sin(v); 38 | 39 | positions.push(...vertex); 40 | 41 | center[0] = settings.radius * Math.cos(u); 42 | center[1] = settings.radius * Math.sin(u); 43 | vec3.subtract(normal, vertex, center); 44 | vec3.normalize(normal, normal); 45 | 46 | normals.push(...normal); 47 | 48 | uvs.push(i / settings.tubularSegments); 49 | uvs.push(j / settings.radialSegments); 50 | } 51 | } 52 | 53 | for (let j = 1; j <= settings.radialSegments; j++) { 54 | for (let i = 1; i <= settings.tubularSegments; i++) { 55 | const a = (settings.tubularSegments + 1) * j + (i - 1); 56 | const b = (settings.tubularSegments + 1) * (j - 1) + (i - 1); 57 | const c = (settings.tubularSegments + 1) * (j - 1) + i; 58 | const d = (settings.tubularSegments + 1) * j + i; 59 | 60 | indices.push(a, b, d); 61 | indices.push(b, c, d); 62 | } 63 | } 64 | 65 | return { 66 | positions, 67 | indices, 68 | normals, 69 | uvs, 70 | }; 71 | } 72 | } 73 | 74 | export default Torus; 75 | -------------------------------------------------------------------------------- /packages/geometries/src/torusknot/index.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | 3 | class TorusKnot { 4 | constructor(props) { 5 | const settings = Object.assign( 6 | {}, 7 | { 8 | radius: 0.5, 9 | tube: 0.2, 10 | tubularSegments: 64, 11 | radialSegments: 6, 12 | p: 2, 13 | q: 3, 14 | }, 15 | props 16 | ); 17 | 18 | const positions = []; 19 | const indices = []; 20 | const normals = []; 21 | const uvs = []; 22 | 23 | const vertex = vec3.create(); 24 | const normal = vec3.create(); 25 | 26 | const P1 = vec3.create(); 27 | const P2 = vec3.create(); 28 | 29 | const B = vec3.create(); 30 | const T = vec3.create(); 31 | const N = vec3.create(); 32 | 33 | for (let i = 0; i <= settings.tubularSegments; i++) { 34 | const u = (i / settings.tubularSegments) * settings.p * Math.PI * 2; 35 | this.calculatePositionOnCurve( 36 | u, 37 | settings.p, 38 | settings.q, 39 | settings.radius, 40 | P1 41 | ); 42 | this.calculatePositionOnCurve( 43 | u + 0.01, 44 | settings.p, 45 | settings.q, 46 | settings.radius, 47 | P2 48 | ); 49 | 50 | vec3.subtract(T, P2, P1); 51 | vec3.add(N, P2, P1); 52 | vec3.cross(B, T, N); 53 | vec3.cross(N, B, T); 54 | 55 | vec3.normalize(B, B); 56 | vec3.normalize(N, N); 57 | 58 | for (let j = 0; j <= settings.radialSegments; j++) { 59 | const v = (j / settings.radialSegments) * Math.PI * 2; 60 | const cx = -settings.tube * Math.cos(v); 61 | const cy = settings.tube * Math.sin(v); 62 | 63 | vertex[0] = P1[0] + (cx * N[0] + cy * B[0]); 64 | vertex[1] = P1[1] + (cx * N[1] + cy * B[1]); 65 | vertex[2] = P1[2] + (cx * N[2] + cy * B[2]); 66 | positions.push(...vertex); 67 | 68 | vec3.subtract(normal, vertex, P1); 69 | vec3.normalize(normal, normal); 70 | normals.push(...normal); 71 | 72 | uvs.push( 73 | i / settings.tubularSegments, 74 | j / settings.radialSegments 75 | ); 76 | } 77 | } 78 | 79 | for (let j = 1; j <= settings.tubularSegments; j++) { 80 | for (let i = 1; i <= settings.radialSegments; i++) { 81 | const a = (settings.radialSegments + 1) * (j - 1) + (i - 1); 82 | const b = (settings.radialSegments + 1) * j + (i - 1); 83 | const c = (settings.radialSegments + 1) * j + i; 84 | const d = (settings.radialSegments + 1) * (j - 1) + i; 85 | 86 | indices.push(a, b, d); 87 | indices.push(b, c, d); 88 | } 89 | } 90 | 91 | return { 92 | positions, 93 | indices, 94 | normals, 95 | uvs, 96 | }; 97 | } 98 | 99 | calculatePositionOnCurve(u, p, q, radius, position) { 100 | const cu = Math.cos(u); 101 | const su = Math.sin(u); 102 | const quOverP = (q / p) * u; 103 | const cs = Math.cos(quOverP); 104 | 105 | position[0] = radius * (2 + cs) * 0.5 * cu; 106 | position[1] = radius * (2 + cs) * su * 0.5; 107 | position[2] = radius * Math.sin(quOverP) * 0.5; 108 | } 109 | } 110 | 111 | export default TorusKnot; 112 | -------------------------------------------------------------------------------- /packages/geometries/src/utils/merge.js: -------------------------------------------------------------------------------- 1 | export const merge = (...props) => { 2 | console.log('merge', props); 3 | 4 | const positions = []; 5 | const indices = []; 6 | const normals = []; 7 | const uvs = []; 8 | 9 | return { 10 | positions, 11 | indices, 12 | normals, 13 | uvs, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/physics/README.md: -------------------------------------------------------------------------------- 1 | # lowww-physics 2 | Adds geometries for the [lowww](https://github.com/andrevenancio/lowww) engine. 3 | 4 | ## Installation 5 | `npm install --save lowww-physics` 6 | 7 | 8 | ## Usage 9 | ```javascript 10 | import { Renderer, Scene, cameras, Mesh } from 'lowww-core'; 11 | import { Icosahedron } from 'lowww-geometries'; 12 | 13 | let renderer; 14 | let camera; 15 | let scene; 16 | let mesh; 17 | 18 | init(); 19 | update(); 20 | 21 | const init = () => { 22 | renderer = new Renderer(); 23 | renderer.setSize(400, 300); 24 | document.body.appendChild(renderer.domElement); 25 | 26 | camera = new cameras.Perspective(); 27 | camera.position.set(0, 0, 500); 28 | 29 | scene = new Scene(); 30 | 31 | const geometry = new Icosahedron({ radius: 10, detail: 1 }); 32 | mesh = new Mesh({ geometry }); 33 | scene.add(mesh); 34 | }; 35 | 36 | const update = () => { 37 | renderer.render(scene, camera); 38 | requestAnimationFrame(update.bind(this)); 39 | }; 40 | ``` 41 | 42 | ## TODO 43 | implement Octree for sorting bodies. 44 | (https://github.com/yomotsu/meshwalk.js/blob/master/src/core/Octree.js) 45 | Will improve performance of loops: 46 | ``` 47 | for (let i = 0; i < this.bodies.length - 1; i++) { 48 | for (let j = i+1; j < this.bodies.length; j++) { 49 | // check collisions 50 | } 51 | } 52 | ``` 53 | 54 | 55 | ## License 56 | MIT 57 | -------------------------------------------------------------------------------- /packages/physics/package.json: -------------------------------------------------------------------------------- 1 | {"name":"lowww-physics","description":"WebGL 2 Engine extension","author":"Andre Venancio (info@andrevenancio.com)","version":"1.1.5","main":"src/index.js","module":"build/physics.module.js","repository":"git@github.com:andrevenancio/lowww.git","scripts":{"test":"echo 'Error: no test specified' && exit 0"},"devDependencies":{},"dependencies":{"gl-matrix":"^2.5.1"}} -------------------------------------------------------------------------------- /packages/physics/src/colliders/aabb-collider.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import { AABB_COLLIDER } from '../constants'; 3 | 4 | class AABBCollider { 5 | constructor(params = {}) { 6 | Object.assign( 7 | this, 8 | { 9 | type: AABB_COLLIDER, 10 | width: 1, 11 | height: 1, 12 | depth: 1, 13 | bounds: vec3.create(), 14 | }, 15 | params 16 | ); 17 | } 18 | 19 | updateBounds(position) { 20 | const width = this.width / 2; 21 | const height = this.height / 2; 22 | const depth = this.depth / 2; 23 | 24 | // world space 25 | this.left = position[0] - width; 26 | this.right = position[0] + width; 27 | 28 | this.top = position[1] + height; 29 | this.bottom = position[1] - height; 30 | 31 | this.front = position[2] + depth; 32 | this.back = position[2] - depth; 33 | 34 | // local space 35 | this.bounds[0] = this.width; 36 | this.bounds[1] = this.height; 37 | this.bounds[2] = this.depth; 38 | } 39 | } 40 | 41 | export default AABBCollider; 42 | -------------------------------------------------------------------------------- /packages/physics/src/colliders/sphere-collider.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import { SPHERE_COLLIDER } from '../constants'; 3 | 4 | class SphereCollider { 5 | constructor(params = {}) { 6 | Object.assign( 7 | this, 8 | { 9 | type: SPHERE_COLLIDER, 10 | radius: 1, 11 | bounds: vec3.create(), 12 | }, 13 | params 14 | ); 15 | } 16 | 17 | updateBounds(position) { 18 | // world space 19 | this.left = position[0] - this.radius; 20 | this.right = position[0] + this.radius; 21 | 22 | this.top = position[1] + this.radius; 23 | this.bottom = position[1] - this.radius; 24 | 25 | this.front = position[2] + this.radius; 26 | this.back = position[2] - this.radius; 27 | 28 | // local space 29 | this.bounds[0] = this.radius; 30 | this.bounds[1] = this.radius; 31 | this.bounds[2] = this.radius; 32 | } 33 | } 34 | 35 | export default SphereCollider; 36 | -------------------------------------------------------------------------------- /packages/physics/src/constants.js: -------------------------------------------------------------------------------- 1 | // id's 2 | export const SPHERE_COLLIDER = 'sphere-collider'; 3 | export const AABB_COLLIDER = 'aabb-collider'; 4 | export const PLANE_COLLIDER = 'plane-collider'; 5 | export const RIGID_BODY = 'rigid-body'; 6 | export const FORCE = 'force'; 7 | 8 | // default values 9 | export const DEFAULT_TIMESTEP = 1 / 180; 10 | -------------------------------------------------------------------------------- /packages/physics/src/core/force.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import { FORCE } from '../constants'; 3 | 4 | class Force { 5 | constructor(x = 0, y = 0, z = 0) { 6 | this.type = FORCE; 7 | this.data = vec3.fromValues(x, y, z); 8 | } 9 | } 10 | 11 | export default Force; 12 | -------------------------------------------------------------------------------- /packages/physics/src/core/rigid-body.js: -------------------------------------------------------------------------------- 1 | import { vec3 } from 'gl-matrix'; 2 | import { RIGID_BODY, SPHERE_COLLIDER, AABB_COLLIDER } from '../constants'; 3 | 4 | class RigidBody { 5 | constructor(params) { 6 | if (!params.collider) { 7 | throw new Error('Please provide a collider'); 8 | } 9 | 10 | if (!params.mesh) { 11 | throw new Error('Please provide a mesh'); 12 | } 13 | 14 | Object.assign( 15 | this, 16 | { 17 | type: RIGID_BODY, 18 | awake: true, 19 | lineardrag: 0.999, 20 | dynamic: true, 21 | velocity: vec3.create(), 22 | acceleration: vec3.create(), 23 | position: vec3.create(), 24 | force: vec3.create(), 25 | }, 26 | params 27 | ); 28 | 29 | // copy mesh position 30 | vec3.copy(this.position, this.mesh.position.data); 31 | } 32 | 33 | getInversemass() { 34 | return 1 / this.getMass(); 35 | } 36 | 37 | getMass() { 38 | switch (this.collider.type) { 39 | case SPHERE_COLLIDER: 40 | return this.collider.radius; 41 | case AABB_COLLIDER: 42 | return 1; 43 | default: 44 | console.warn('unknown collider'); 45 | return 1; 46 | } 47 | } 48 | 49 | // copies world force into body 50 | addForce(force) { 51 | vec3.copy(this.force, force); 52 | } 53 | 54 | integrate(deltatime) { 55 | if (!this.awake || !this.dynamic) { 56 | return; 57 | } 58 | 59 | // calculate acceleration 60 | const mass = this.getMass(); 61 | this.acceleration[0] = this.force[0] / mass; 62 | this.acceleration[1] = this.force[1] / mass; 63 | this.acceleration[2] = this.force[2] / mass; 64 | 65 | // adding acceleration to velocity 66 | vec3.scaleAndAdd( 67 | this.velocity, 68 | this.velocity, 69 | this.acceleration, 70 | deltatime 71 | ); 72 | 73 | // adding velocity to position 74 | vec3.scaleAndAdd( 75 | this.position, 76 | this.position, 77 | this.velocity, 78 | deltatime 79 | ); 80 | 81 | // add drag to velocity 82 | this.velocity[0] *= this.lineardrag; 83 | this.velocity[1] *= this.lineardrag; 84 | this.velocity[2] *= this.lineardrag; 85 | } 86 | 87 | updateBounds() { 88 | this.collider.updateBounds(this.position); 89 | } 90 | 91 | render() { 92 | vec3.copy(this.mesh.position.data, this.position); 93 | } 94 | } 95 | 96 | export default RigidBody; 97 | -------------------------------------------------------------------------------- /packages/physics/src/index.js: -------------------------------------------------------------------------------- 1 | // world 2 | import World from './core/world'; 3 | 4 | // bodies 5 | import RigidBody from './core/rigid-body'; 6 | 7 | // colliders 8 | import SphereCollider from './colliders/sphere-collider'; 9 | import AABBCollider from './colliders/aabb-collider'; 10 | 11 | // forces 12 | import Force from './core/force'; 13 | 14 | export { World, RigidBody, SphereCollider, AABBCollider, Force }; 15 | -------------------------------------------------------------------------------- /packages/physics/src/workers/todo.js: -------------------------------------------------------------------------------- 1 | /* global Worker, Blob */ 2 | const worker = new Worker( 3 | URL.createObjectURL( 4 | new Blob([ 5 | ` 6 | onmessage = event => { 7 | postMessage('Hello ' + event.data); 8 | }; 9 | `, 10 | ]) 11 | ) 12 | ); 13 | worker.onmessage = e => { 14 | console.log(e.data); 15 | }; 16 | worker.postMessage('World'); 17 | -------------------------------------------------------------------------------- /packages/postprocessing/README.md: -------------------------------------------------------------------------------- 1 | # lowww-postprocessing 2 | Allows postprocessing effects on [lowww](https://github.com/andrevenancio/lowww) engine. 3 | 4 | ## Installation 5 | `npm install --save lowww-postprocessing` 6 | 7 | 8 | ## Usage 9 | ```javascript 10 | import { Composer, Scene, cameras, Pass, shaders } from 'lowww-core'; 11 | import { Icosahedron } from 'lowww-geometries'; 12 | import { Noise, tiltShift } from 'lowww-postprocessing'; 13 | 14 | let composer; 15 | let camera; 16 | let scene; 17 | let mesh; 18 | 19 | let noise; 20 | let tiltshiftHorizontal; 21 | let tiltshiftVertical; 22 | 23 | init(); 24 | update(); 25 | 26 | const init = () => { 27 | composer = new Composer(); 28 | composer.setSize(400, 300); 29 | document.body.appendChild(composer.domElement); 30 | 31 | camera = new cameras.Perspective(); 32 | camera.position.set(0, 0, 500); 33 | 34 | scene = new Scene(); 35 | 36 | const geometry = new Icosahedron({ radius: 100, detail: 1 }); 37 | mesh = new Mesh({ geometry }); 38 | scene.add(mesh); 39 | 40 | noise = new Pass(Noise); 41 | tiltshiftHorizontal = new Pass(tiltShift.Horizontal); 42 | tiltshiftVertical = new Pass(tiltShift.Vertical); 43 | 44 | composer.pass(noise); 45 | composer.pass(tiltshiftHorizontal); 46 | composer.pass(tiltshiftVertical); 47 | composer.compile(); 48 | }; 49 | 50 | const update = () => { 51 | composer.render(scene, camera); 52 | requestAnimationFrame(update.bind(this)); 53 | }; 54 | ``` 55 | 56 | 57 | ## License 58 | MIT 59 | -------------------------------------------------------------------------------- /packages/postprocessing/package.json: -------------------------------------------------------------------------------- 1 | {"name":"lowww-postprocessing","description":"WebGL 2 Engine extension","author":"Andre Venancio (info@andrevenancio.com)","version":"1.1.5","main":"src/index.js","module":"build/postprocessing.module.js","repository":"git@github.com:andrevenancio/lowww.git","scripts":{"test":"echo 'Error: no test specified' && exit 0"},"devDependencies":{},"dependencies":{"gl-matrix":"^2.5.1"}} -------------------------------------------------------------------------------- /packages/postprocessing/src/bleach/index.js: -------------------------------------------------------------------------------- 1 | const Bleach = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_opacity: { type: 'float', value: 1.0 }, 5 | }, 6 | 7 | vertex: ` 8 | out vec2 v_uv; 9 | void main() { 10 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 11 | v_uv = a_uv; 12 | }`, 13 | 14 | fragment: ` 15 | in vec2 v_uv; 16 | 17 | uniform sampler2D u_input; 18 | uniform float u_opacity; 19 | 20 | void main() { 21 | 22 | vec4 base = texture(u_input, v_uv); 23 | 24 | vec3 lumCoeff = vec3(0.25, 0.65, 0.1); 25 | float lum = dot(lumCoeff, base.rgb); 26 | vec3 blend = vec3(lum); 27 | 28 | float L = min(1.0, max(0.0, 10.0 * (lum - 0.45))); 29 | 30 | vec3 result1 = 2.0 * base.rgb * blend; 31 | vec3 result2 = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base.rgb); 32 | 33 | vec3 newColor = mix(result1, result2, L); 34 | 35 | float A2 = u_opacity * base.a; 36 | vec3 mixRGB = A2 * newColor.rgb; 37 | mixRGB += ((1.0 - A2) * base.rgb); 38 | 39 | outColor = vec4(mixRGB, base.a); 40 | }`, 41 | }; 42 | 43 | export default Bleach; 44 | -------------------------------------------------------------------------------- /packages/postprocessing/src/blur/horizontal.js: -------------------------------------------------------------------------------- 1 | const Horizontal = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_amount: { type: 'float', value: 512 }, 5 | }, 6 | 7 | vertex: ` 8 | out vec2 v_uv; 9 | void main() { 10 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 11 | v_uv = a_uv; 12 | }`, 13 | 14 | fragment: ` 15 | in vec2 v_uv; 16 | 17 | uniform sampler2D u_input; 18 | uniform float u_amount; 19 | 20 | void main() { 21 | vec4 sum = vec4(0.0); 22 | float hh = (1.0 / u_amount); 23 | 24 | sum += texture(u_input, vec2(v_uv.x - 4.0 * hh, v_uv.y)) * 0.051; 25 | sum += texture(u_input, vec2(v_uv.x - 3.0 * hh, v_uv.y)) * 0.0918; 26 | sum += texture(u_input, vec2(v_uv.x - 2.0 * hh, v_uv.y)) * 0.12245; 27 | sum += texture(u_input, vec2(v_uv.x - 1.0 * hh, v_uv.y)) * 0.1531; 28 | sum += texture(u_input, vec2(v_uv.x, v_uv.y ) ) * 0.1633; 29 | sum += texture(u_input, vec2(v_uv.x + 1.0 * hh, v_uv.y)) * 0.1531; 30 | sum += texture(u_input, vec2(v_uv.x + 2.0 * hh, v_uv.y)) * 0.12245; 31 | sum += texture(u_input, vec2(v_uv.x + 3.0 * hh, v_uv.y)) * 0.0918; 32 | sum += texture(u_input, vec2(v_uv.x + 4.0 * hh, v_uv.y)) * 0.051; 33 | 34 | outColor = sum; 35 | }`, 36 | }; 37 | 38 | export default Horizontal; 39 | -------------------------------------------------------------------------------- /packages/postprocessing/src/blur/index.js: -------------------------------------------------------------------------------- 1 | import Horizontal from './horizontal'; 2 | import Vertical from './vertical'; 3 | 4 | export { Horizontal, Vertical }; 5 | -------------------------------------------------------------------------------- /packages/postprocessing/src/blur/vertical.js: -------------------------------------------------------------------------------- 1 | const Vertical = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_amount: { type: 'float', value: 512 }, 5 | }, 6 | 7 | vertex: ` 8 | out vec2 v_uv; 9 | void main() { 10 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 11 | v_uv = a_uv; 12 | }`, 13 | 14 | fragment: ` 15 | in vec2 v_uv; 16 | 17 | uniform sampler2D u_input; 18 | uniform float u_amount; 19 | 20 | void main() { 21 | vec4 sum = vec4(0.0); 22 | float vv = (1.0 / u_amount); 23 | 24 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 4.0 * vv)) * 0.051; 25 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 3.0 * vv)) * 0.0918; 26 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 2.0 * vv)) * 0.12245; 27 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 1.0 * vv)) * 0.1531; 28 | sum += texture(u_input, vec2(v_uv.x, v_uv.y ) ) * 0.1633; 29 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 1.0 * vv)) * 0.1531; 30 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 2.0 * vv)) * 0.12245; 31 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 3.0 * vv)) * 0.0918; 32 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 4.0 * vv)) * 0.051; 33 | 34 | outColor = sum; 35 | }`, 36 | }; 37 | 38 | export default Vertical; 39 | -------------------------------------------------------------------------------- /packages/postprocessing/src/brightness/index.js: -------------------------------------------------------------------------------- 1 | const Brightness = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_treshold: { type: 'float', value: 0.0 }, 5 | }, 6 | 7 | vertex: ` 8 | out vec2 v_uv; 9 | void main() { 10 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 11 | v_uv = a_uv; 12 | }`, 13 | 14 | fragment: ` 15 | in vec2 v_uv; 16 | 17 | uniform sampler2D u_input; 18 | uniform float u_treshold; 19 | 20 | void main() { 21 | // relative luminance 22 | vec3 lum = vec3(0.2126, 0.7152, 0.0722); 23 | vec4 c = texture(u_input, v_uv); 24 | 25 | float luminance = dot(lum, c.xyz); 26 | luminance = max(0.0, luminance - u_treshold); 27 | c.xyz *= sign(luminance); 28 | c.a = 1.0; 29 | 30 | outColor = c; 31 | }`, 32 | }; 33 | 34 | export default Brightness; 35 | -------------------------------------------------------------------------------- /packages/postprocessing/src/dot-screen/index.js: -------------------------------------------------------------------------------- 1 | const DotScreen = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_size: { type: 'float', value: 256 }, 5 | u_center: { type: 'vec2', value: [0.5, 0.5] }, 6 | u_angle: { type: 'float', value: 1.57 }, 7 | u_scale: { type: 'float', value: 1.0 }, 8 | }, 9 | 10 | vertex: ` 11 | out vec2 v_uv; 12 | void main() { 13 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 14 | v_uv = a_uv; 15 | }`, 16 | 17 | fragment: ` 18 | in vec2 v_uv; 19 | 20 | uniform sampler2D u_input; 21 | 22 | uniform vec2 u_center; 23 | uniform float u_angle; 24 | uniform float u_scale; 25 | uniform float u_size; 26 | 27 | float pattern() { 28 | float s = sin(u_angle), c = cos(u_angle); 29 | 30 | vec2 tex = v_uv * vec2(u_size) - u_center; 31 | vec2 point = vec2(c * tex.x - s * tex.y, s * tex.x + c * tex.y) * u_scale; 32 | 33 | return (sin(point.x) * sin(point.y)) * 4.0; 34 | } 35 | 36 | void main() { 37 | vec4 color = texture(u_input, v_uv); 38 | 39 | float average = (color.r + color.g + color.b) / 3.0; 40 | 41 | outColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); 42 | }`, 43 | }; 44 | 45 | export default DotScreen; 46 | -------------------------------------------------------------------------------- /packages/postprocessing/src/glitch/index.js: -------------------------------------------------------------------------------- 1 | // inspired by: https://www.shadertoy.com/view/4t23Rc 2 | const Glitch = { 3 | uniforms: { 4 | u_input: { type: 'sampler2D', value: null }, 5 | u_amplitude: { type: 'float', value: 3.0 }, 6 | u_speed: { type: 'float', value: 2.0 }, 7 | }, 8 | 9 | vertex: ` 10 | out vec2 v_uv; 11 | void main() { 12 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 13 | v_uv = a_uv; 14 | }`, 15 | 16 | fragment: ` 17 | in vec2 v_uv; 18 | 19 | uniform sampler2D u_input; 20 | uniform float u_speed; 21 | uniform float u_amplitude; 22 | 23 | vec4 rgbShift(vec2 p, vec4 shift) { 24 | shift *= 2.0 * shift.w - 1.0; 25 | vec2 rs = vec2(shift.x, -shift.y); 26 | vec2 gs = vec2(shift.y, -shift.z); 27 | vec2 bs = vec2(shift.z, -shift.x); 28 | 29 | float r = texture(u_input, p + rs).x; 30 | float g = texture(u_input, p + gs).y; 31 | float b = texture(u_input, p + bs).z; 32 | 33 | return vec4(r, g, b, 1.0); 34 | } 35 | 36 | float rand(vec2 uv) { 37 | return fract(sin(dot(uv.xy, vec2(12.9898, 78.233))) * 43758.5453); 38 | } 39 | 40 | vec4 noise(vec2 n) { 41 | float r = rand(n.xy + 0.1); 42 | float g = rand(n.xy + 0.2); 43 | float b = rand(n.xy + 0.3); 44 | return vec4(r - 0.5, g - 0.5, b - 0.5, 1.0); 45 | } 46 | 47 | vec4 vec4pow(vec4 v, float p) { 48 | return vec4(pow(v.x, p), pow(v.y, p), pow(v.z, p), v.w); 49 | } 50 | 51 | void main() { 52 | vec4 color = texture(u_input, v_uv); 53 | 54 | vec4 c = vec4(0.0, 0.0, 0.0, 1.0); 55 | 56 | float v = clamp(sin(iGlobalTime * u_speed), 0.0, 1.0); 57 | vec4 shift = vec4pow(noise(vec2(1.0 - v, 0.0)), 8.0) * vec4(u_amplitude, u_amplitude, u_amplitude, 1.0) * v; 58 | 59 | c += rgbShift(v_uv, shift); 60 | 61 | outColor = c; 62 | }`, 63 | }; 64 | 65 | export default Glitch; 66 | -------------------------------------------------------------------------------- /packages/postprocessing/src/hue-saturation/index.js: -------------------------------------------------------------------------------- 1 | const HueSaturation = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_hue: { type: 'float', value: 0.0 }, // -1 to 1 5 | u_saturation: { type: 'float', value: 0.0 }, // -1 to 1 6 | }, 7 | 8 | vertex: ` 9 | out vec2 v_uv; 10 | void main() { 11 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 12 | v_uv = a_uv; 13 | }`, 14 | 15 | fragment: ` 16 | in vec2 v_uv; 17 | 18 | uniform sampler2D u_input; 19 | uniform float u_hue; 20 | uniform float u_saturation; 21 | 22 | void main() { 23 | vec4 color = texture(u_input, v_uv); 24 | float angle = u_hue * 3.14159265; 25 | float s = sin(angle), c = cos(angle); 26 | vec3 weights = (vec3(2.0 * c, -sqrt(3.0) * s - c, sqrt(3.0) * s - c) + 1.0) / 3.0; 27 | float len = length(color.rgb); 28 | color.rgb = vec3( 29 | dot(color.rgb, weights.xyz), 30 | dot(color.rgb, weights.zxy), 31 | dot(color.rgb, weights.yzx) 32 | ); 33 | 34 | float average = (color.r + color.g + color.b) / 3.0; 35 | if (u_saturation > 0.0) { 36 | color.rgb += (average - color.rgb) * (1.0 - 1.0 / (1.001 - u_saturation)); 37 | } else { 38 | color.rgb += (average - color.rgb) * (-u_saturation); 39 | } 40 | 41 | outColor = color; 42 | }`, 43 | }; 44 | 45 | export default HueSaturation; 46 | -------------------------------------------------------------------------------- /packages/postprocessing/src/index.js: -------------------------------------------------------------------------------- 1 | import * as blur from './blur'; 2 | import Bleach from './bleach'; 3 | import Brightness from './brightness'; 4 | import DotScreen from './dot-screen'; 5 | import * as tiltShift from './tilt-shift'; 6 | import Noise from './noise'; 7 | import HueSaturation from './hue-saturation'; 8 | import Glitch from './glitch'; 9 | 10 | export { 11 | blur, 12 | Bleach, 13 | Brightness, 14 | DotScreen, 15 | tiltShift, 16 | Noise, 17 | HueSaturation, 18 | Glitch, 19 | }; 20 | 21 | // resources: 22 | // http://evanw.github.io/glfx.js/demo/ 23 | // http://pixijs.io/pixi-filters/tools/demo/ 24 | // https://github.com/mrdoob/three.js/tree/dev/examples/js/shaders 25 | // https://github.com/spite/Wagner/tree/master/fragment-shaders 26 | // https://shadertoy.com 27 | -------------------------------------------------------------------------------- /packages/postprocessing/src/noise/index.js: -------------------------------------------------------------------------------- 1 | const Noise = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_seed: { type: 'float', value: 0.01 }, 5 | u_amount: { type: 'float', value: 0.5 }, 6 | }, 7 | 8 | vertex: ` 9 | out vec2 v_uv; 10 | void main() { 11 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 12 | v_uv = a_uv; 13 | }`, 14 | 15 | fragment: ` 16 | in vec2 v_uv; 17 | 18 | uniform sampler2D u_input; 19 | uniform float u_seed; 20 | uniform float u_amount; 21 | 22 | float rand(vec2 uv) { 23 | return fract(sin(dot(uv.xy, vec2(12.9898, 78.233))) * 43758.5453); 24 | } 25 | 26 | void main() { 27 | vec4 color = texture(u_input, v_uv); 28 | float random = rand(gl_FragCoord.xy * u_seed); 29 | float diff = (random - 0.5) * u_amount; 30 | 31 | color.r += diff; 32 | color.g += diff; 33 | color.b += diff; 34 | 35 | outColor = color; 36 | }`, 37 | }; 38 | 39 | export default Noise; 40 | -------------------------------------------------------------------------------- /packages/postprocessing/src/tilt-shift/horizontal.js: -------------------------------------------------------------------------------- 1 | const Horizontal = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_amount: { type: 'float', value: 128 }, 5 | u_xscreenpos: { type: 'float', value: 0.5 }, 6 | }, 7 | 8 | vertex: ` 9 | out vec2 v_uv; 10 | void main() { 11 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 12 | v_uv = a_uv; 13 | }`, 14 | 15 | fragment: ` 16 | in vec2 v_uv; 17 | 18 | uniform sampler2D u_input; 19 | uniform float u_amount; 20 | uniform float u_xscreenpos; 21 | 22 | void main() { 23 | vec4 sum = vec4(0.0); 24 | float hh = (1.0 / u_amount) * abs(u_xscreenpos - v_uv.x); 25 | 26 | sum += texture(u_input, vec2(v_uv.x - 4.0 * hh, v_uv.y)) * 0.051; 27 | sum += texture(u_input, vec2(v_uv.x - 3.0 * hh, v_uv.y)) * 0.0918; 28 | sum += texture(u_input, vec2(v_uv.x - 2.0 * hh, v_uv.y)) * 0.12245; 29 | sum += texture(u_input, vec2(v_uv.x - 1.0 * hh, v_uv.y)) * 0.1531; 30 | sum += texture(u_input, vec2(v_uv.x, v_uv.y ) ) * 0.1633; 31 | sum += texture(u_input, vec2(v_uv.x + 1.0 * hh, v_uv.y)) * 0.1531; 32 | sum += texture(u_input, vec2(v_uv.x + 2.0 * hh, v_uv.y)) * 0.12245; 33 | sum += texture(u_input, vec2(v_uv.x + 3.0 * hh, v_uv.y)) * 0.0918; 34 | sum += texture(u_input, vec2(v_uv.x + 4.0 * hh, v_uv.y)) * 0.051; 35 | 36 | outColor = sum; 37 | }`, 38 | }; 39 | 40 | export default Horizontal; 41 | -------------------------------------------------------------------------------- /packages/postprocessing/src/tilt-shift/index.js: -------------------------------------------------------------------------------- 1 | import Horizontal from './horizontal'; 2 | import Vertical from './vertical'; 3 | 4 | export { Horizontal, Vertical }; 5 | -------------------------------------------------------------------------------- /packages/postprocessing/src/tilt-shift/vertical.js: -------------------------------------------------------------------------------- 1 | const Vertical = { 2 | uniforms: { 3 | u_input: { type: 'sampler2D', value: null }, 4 | u_amount: { type: 'float', value: 128 }, 5 | u_yscreenpos: { type: 'float', value: 0.5 }, 6 | }, 7 | 8 | vertex: ` 9 | out vec2 v_uv; 10 | void main() { 11 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 12 | v_uv = a_uv; 13 | }`, 14 | 15 | fragment: ` 16 | in vec2 v_uv; 17 | 18 | uniform sampler2D u_input; 19 | uniform float u_amount; 20 | uniform float u_yscreenpos; 21 | 22 | void main() { 23 | vec4 sum = vec4(0.0); 24 | float vv = (1.0 / u_amount) * abs(u_yscreenpos - v_uv.y); 25 | 26 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 4.0 * vv)) * 0.051; 27 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 3.0 * vv)) * 0.0918; 28 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 2.0 * vv)) * 0.12245; 29 | sum += texture(u_input, vec2(v_uv.x, v_uv.y - 1.0 * vv)) * 0.1531; 30 | sum += texture(u_input, vec2(v_uv.x, v_uv.y ) ) * 0.1633; 31 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 1.0 * vv)) * 0.1531; 32 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 2.0 * vv)) * 0.12245; 33 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 3.0 * vv)) * 0.0918; 34 | sum += texture(u_input, vec2(v_uv.x, v_uv.y + 4.0 * vv)) * 0.051; 35 | 36 | outColor = sum; 37 | }`, 38 | }; 39 | 40 | export default Vertical; 41 | -------------------------------------------------------------------------------- /scripts/node/generate-packages.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | let packageName = ''; 4 | if (process.env.PACKAGE) { 5 | packageName = `-${process.env.PACKAGE}`; 6 | } 7 | 8 | fs.readFile('package.json', 'utf8', (error, text) => { 9 | const pkg = JSON.parse(text); 10 | const json = { 11 | name: `${pkg.name}${packageName}`, 12 | description: 'WebGL 2 Engine extension', 13 | author: pkg.author, 14 | version: pkg.version, 15 | main: 'src/index.js', 16 | module: `build/${process.env.PACKAGE}.module.js`, 17 | repository: 'git@github.com:andrevenancio/lowww.git', 18 | scripts: { 19 | test: 'echo \'Error: no test specified\' && exit 0', 20 | }, 21 | devDependencies: {}, 22 | dependencies: { 23 | 'gl-matrix': '^2.5.1', 24 | }, 25 | }; 26 | fs.writeFile(`packages/${process.env.PACKAGE}/package.json`, JSON.stringify(json), 'utf8', () => {}); 27 | }); 28 | -------------------------------------------------------------------------------- /scripts/node/minify-options.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | let packageName = ''; 4 | if (process.env.PACKAGE) { 5 | packageName = `-${process.env.PACKAGE}`; 6 | } 7 | 8 | fs.readFile('package.json', 'utf8', (error, text) => { 9 | const pkg = JSON.parse(text); 10 | const json = { 11 | toplevel: true, 12 | compress: { 13 | passes: 2, 14 | }, 15 | output: { 16 | beautify: false, 17 | preamble: `/*\n${pkg.name}${packageName} - version: ${pkg.version}\nCopyright © ${(new Date()).getFullYear()} ${pkg.author}\n*/`, 18 | }, 19 | }; 20 | fs.writeFile('scripts/minify-options.json', JSON.stringify(json), 'utf8', () => {}); 21 | }); 22 | -------------------------------------------------------------------------------- /scripts/rollup/examples.development.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import glob from 'glob'; 3 | import path from 'path'; 4 | import resolve from 'rollup-plugin-node-resolve'; 5 | 6 | import copy from './rollup-plugins/copy'; 7 | import html from './rollup-plugins/html'; 8 | 9 | // 1) 10 | // look through all files on the src folder 11 | const SRC = path.join(process.cwd(), 'src'); 12 | const DEV = path.join(process.cwd(), 'dev'); 13 | 14 | const files = glob.sync(path.join(SRC, '**/*.js')).filter((entry) => { 15 | const temp = entry.replace(SRC, '').split('/'); 16 | 17 | // entry point can only be src/EXAMPLE_NAME/index.js, 18 | if (temp[2] === 'index.js') { 19 | return { name: temp[1] }; 20 | } 21 | 22 | return false; 23 | }); 24 | 25 | const examples = files.map((entry) => { 26 | const temp = entry.replace(SRC, '').split('/'); 27 | const name = temp[1]; 28 | 29 | return { 30 | name, 31 | thumb: `img/thumbnails/${name}.jpg`, 32 | url: `${name}.html`, 33 | }; 34 | }); 35 | 36 | 37 | // 2) 38 | // create a rollup config for each example 39 | const configs = files.map((entry) => { 40 | const temp = entry.replace(SRC, '').split('/'); 41 | const name = temp[1]; 42 | 43 | const setup = { 44 | input: path.join(SRC, name, 'index.js'), 45 | output: { 46 | format: 'umd', 47 | name: 'example', 48 | file: path.join(DEV, 'js', `${name}.js`), 49 | }, 50 | watch: { 51 | include: [ 52 | path.join(SRC, 'template.js'), 53 | path.join(SRC, name, '**'), 54 | ], 55 | }, 56 | plugins: [ 57 | resolve(), 58 | babel(), 59 | copy([ 60 | { from: path.join(SRC, 'static'), to: path.join(DEV) }, 61 | ]), 62 | html({ 63 | output: path.join(DEV, `${name}.html`), 64 | metadata: { 65 | title: name, 66 | }, 67 | css: [ 68 | 'css/style.css', 69 | ], 70 | js: [ 71 | 'https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.1/dat.gui.min.js', 72 | 'https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.1/TweenLite.min.js', 73 | '../packages/controls/build/controls.js', 74 | '../packages/core/build/core.js', 75 | '../packages/geometries/build/geometries.js', 76 | '../packages/postprocessing/build/postprocessing.js', 77 | '../packages/physics/build/physics.js', 78 | `js/${name}.js`, 79 | ], 80 | }), 81 | html({ 82 | output: path.join(DEV, 'index.html'), 83 | isIndex: true, 84 | metadata: { 85 | title: 'DEVELOPMENT', 86 | }, 87 | css: [ 88 | 'css/style.css', 89 | ], 90 | examples, 91 | }), 92 | ], 93 | }; 94 | 95 | return Object.assign({}, setup); 96 | }); 97 | 98 | // 3) 99 | // export an array of configs 100 | export default configs; 101 | -------------------------------------------------------------------------------- /scripts/rollup/examples.production.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import glob from 'glob'; 3 | import path from 'path'; 4 | import resolve from 'rollup-plugin-node-resolve'; 5 | 6 | import copy from './rollup-plugins/copy'; 7 | import html from './rollup-plugins/html'; 8 | 9 | // 1) 10 | // look through all files on the src folder 11 | const SRC = path.join(process.cwd(), 'src'); 12 | const DEV = path.join(process.cwd(), 'site'); 13 | 14 | const files = glob.sync(path.join(SRC, '**/*.js')).filter((entry) => { 15 | const temp = entry.replace(SRC, '').split('/'); 16 | 17 | // entry point can only be src/EXAMPLE_NAME/index.js, 18 | if (temp[2] === 'index.js') { 19 | return { name: temp[1] }; 20 | } 21 | 22 | return false; 23 | }); 24 | 25 | const examples = files.map((entry) => { 26 | const temp = entry.replace(SRC, '').split('/'); 27 | const name = temp[1]; 28 | 29 | return { 30 | name, 31 | thumb: `img/thumbnails/${name}.jpg`, 32 | url: `${name}.html`, 33 | }; 34 | }); 35 | 36 | // 2) 37 | // create a rollup config for each example 38 | const configs = files.map((entry) => { 39 | const temp = entry.replace(SRC, '').split('/'); 40 | const name = temp[1]; 41 | 42 | const setup = { 43 | input: path.join(SRC, name, 'index.js'), 44 | output: { 45 | format: 'umd', 46 | name: 'example', 47 | file: path.join(DEV, 'js', `${name}.js`), 48 | }, 49 | plugins: [ 50 | babel(), 51 | resolve(), 52 | copy([ 53 | { from: path.join(SRC, 'static'), to: path.join(DEV) }, 54 | ]), 55 | html({ 56 | output: path.join(DEV, `${name}.html`), 57 | minify: true, 58 | metadata: { 59 | title: name, 60 | description: `lowww engine ${name} example.`, 61 | thumbnail: `https://andrevenancio.github.io/lowww/img/thumbnails/${name}.jpg`, 62 | url: `https://andrevenancio.github.io/lowww/${name}.html`, 63 | }, 64 | css: [ 65 | 'css/style.css', 66 | ], 67 | js: [ 68 | 'https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.1/dat.gui.min.js', 69 | 'https://rawgit.com/andrevenancio/lowww/master/packages/controls/build/controls.min.js', 70 | 'https://rawgit.com/andrevenancio/lowww/master/packages/core/build/core.min.js', 71 | 'https://rawgit.com/andrevenancio/lowww/master/packages/geometries/build/geometries.min.js', 72 | 'https://rawgit.com/andrevenancio/lowww/master/packages/postprocessing/build/postprocessing.min.js', 73 | 'https://rawgit.com/andrevenancio/lowww/master/packages/physics/build/physics.min.js', 74 | `js/${name}.js`, 75 | ], 76 | }), 77 | html({ 78 | output: path.join(DEV, 'index.html'), 79 | minify: true, 80 | isIndex: true, 81 | metadata: { 82 | title: 'lowww', 83 | description: 'lowww engine example.', 84 | thumbnail: 'https://andrevenancio.github.io/lowww/img/thumbnails/facebook.jpg', 85 | url: 'https://andrevenancio.github.io/lowww/', 86 | }, 87 | css: [ 88 | 'css/style.css', 89 | ], 90 | examples, 91 | }), 92 | ], 93 | }; 94 | 95 | return Object.assign({}, setup); 96 | }); 97 | 98 | // 3) 99 | // export an array of configs 100 | export default configs; 101 | -------------------------------------------------------------------------------- /scripts/rollup/rollup-plugins/copy.js: -------------------------------------------------------------------------------- 1 | import fse from 'fse'; 2 | 3 | export default function replace(files) { 4 | return { 5 | name: 'copy', 6 | 7 | onwrite() { 8 | files.forEach((file) => { 9 | if (file.isFile) { 10 | fse.copyFile(file.from, file.to); 11 | } else { 12 | fse.copydir(file.from, file.to); 13 | } 14 | }); 15 | }, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /scripts/rollup/rollup.es5.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import path from 'path'; 3 | import replace from 'rollup-plugin-replace'; 4 | import resolve from 'rollup-plugin-node-resolve'; 5 | 6 | import pkg from '../../package.json'; 7 | 8 | const packageName = process.env.PACKAGE; 9 | const packagePath = path.join(process.cwd(), 'packages', packageName); 10 | const packageVersion = JSON.stringify(pkg.version); 11 | 12 | export default { 13 | input: path.join(packagePath, 'src', 'index.js'), 14 | output: { 15 | format: 'umd', 16 | name: `lowww.${packageName}`, 17 | file: path.join(packagePath, 'build', `${packageName}.js`), 18 | }, 19 | watch: { 20 | include: path.join(packagePath, 'src', '**'), 21 | }, 22 | plugins: [ 23 | replace({ 24 | __LIBRARY__: JSON.stringify(packageName), 25 | __VERSION__: packageVersion, 26 | }), 27 | resolve(), 28 | babel(), 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /scripts/rollup/rollup.es6.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import path from 'path'; 3 | import replace from 'rollup-plugin-replace'; 4 | import resolve from 'rollup-plugin-node-resolve'; 5 | 6 | import pkg from '../../package.json'; 7 | 8 | const packageName = process.env.PACKAGE; 9 | const packagePath = path.join(process.cwd(), 'packages', packageName); 10 | const packageVersion = JSON.stringify(pkg.version); 11 | 12 | export default { 13 | input: path.join(packagePath, 'src', 'index.js'), 14 | output: { 15 | format: 'es', 16 | name: `lowww.${packageName}`, 17 | file: path.join(packagePath, 'build', `${packageName}.module.js`), 18 | }, 19 | watch: { 20 | include: path.join(packagePath, 'src', '**'), 21 | }, 22 | plugins: [ 23 | replace({ 24 | __LIBRARY__: JSON.stringify(packageName), 25 | __VERSION__: packageVersion, 26 | }), 27 | resolve(), 28 | babel(), // allows arrow functions 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /site/basic.html: -------------------------------------------------------------------------------- 1 | basicback source -------------------------------------------------------------------------------- /site/clipping-planes.html: -------------------------------------------------------------------------------- 1 | clipping-planesback source -------------------------------------------------------------------------------- /site/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | background-color: #000; 4 | color: #fff; 5 | font-family: sans-serif; 6 | font-size: 14px; 7 | -moz-osx-font-smoothing: grayscale; 8 | -webkit-font-smoothing: antialiased; 9 | } 10 | 11 | canvas { 12 | display: block; 13 | } 14 | 15 | a { 16 | display: block; 17 | color: #fff; 18 | text-decoration: none; 19 | line-height: 20px; 20 | } 21 | 22 | a:hover { 23 | color: #fff; 24 | } 25 | 26 | a.back, 27 | a.source { 28 | position: fixed; 29 | background-color: rgba(255, 255, 255, 0.05); 30 | padding: 3px 6px; 31 | border-radius: 4px; 32 | font-family: monospace; 33 | font-size: 12px; 34 | } 35 | 36 | a.back:hover, 37 | a.source:hover { 38 | background-color: rgba(255, 255, 255, 0.1); 39 | } 40 | 41 | a.back { 42 | top: 20px; 43 | left: 20px; 44 | } 45 | 46 | a.source { 47 | bottom: 20px; 48 | right: 20px; 49 | } 50 | 51 | a.thumb { 52 | position: relative; 53 | display: inline-block; 54 | border: 1px solid #333; 55 | margin: 10px; 56 | } 57 | a.thumb img { 58 | width: 200px; 59 | height: 150px; 60 | opacity: 1; 61 | transition: all 0.15s ease-in-out; 62 | } 63 | a.thumb p { 64 | position: absolute; 65 | top: 50%; 66 | left: 50%; 67 | opacity: 0; 68 | transform: translateX(-50%) translateY(-100%); 69 | text-align: center; 70 | transition: all 0.15s ease-in-out; 71 | } 72 | 73 | a.thumb:hover img { 74 | opacity: 0.25; 75 | } 76 | 77 | a.thumb:hover p { 78 | top: 50%; 79 | opacity: 1; 80 | } 81 | -------------------------------------------------------------------------------- /site/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/favicon.ico -------------------------------------------------------------------------------- /site/geometries.html: -------------------------------------------------------------------------------- 1 | geometriesback source -------------------------------------------------------------------------------- /site/img/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/facebook.png -------------------------------------------------------------------------------- /site/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /site/img/matcap/black-gloss.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/matcap/black-gloss.jpg -------------------------------------------------------------------------------- /site/img/matcap/skin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/matcap/skin.jpg -------------------------------------------------------------------------------- /site/img/matcap/world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/matcap/world.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/basic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/basic.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/clipping-planes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/clipping-planes.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/geometries.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/geometries.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/instancing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/instancing.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/materials.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/materials.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/modify.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/modify.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/postprocessing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/postprocessing.jpg -------------------------------------------------------------------------------- /site/img/thumbnails/render-to-texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/thumbnails/render-to-texture.jpg -------------------------------------------------------------------------------- /site/img/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/twitter.png -------------------------------------------------------------------------------- /site/img/uv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/site/img/uv.png -------------------------------------------------------------------------------- /site/index.html: -------------------------------------------------------------------------------- 1 | lowww -------------------------------------------------------------------------------- /site/instancing.html: -------------------------------------------------------------------------------- 1 | instancingback source -------------------------------------------------------------------------------- /site/materials.html: -------------------------------------------------------------------------------- 1 | materialsback source -------------------------------------------------------------------------------- /site/modify.html: -------------------------------------------------------------------------------- 1 | modifyback source -------------------------------------------------------------------------------- /site/physics.html: -------------------------------------------------------------------------------- 1 | physicsback source -------------------------------------------------------------------------------- /site/postprocessing.html: -------------------------------------------------------------------------------- 1 | postprocessingback source -------------------------------------------------------------------------------- /site/render-to-texture.html: -------------------------------------------------------------------------------- 1 | render-to-textureback source -------------------------------------------------------------------------------- /src/_prism/index.js: -------------------------------------------------------------------------------- 1 | import Template from '../template'; 2 | import { L } from './letters'; 3 | 4 | const { Renderer, Scene, cameras } = lowww.core; 5 | const { Orbit } = lowww.controls; 6 | 7 | class Main extends Template { 8 | setup() { 9 | this.renderer = new Renderer(); 10 | document.body.appendChild(this.renderer.domElement); 11 | 12 | this.scene = new Scene(); 13 | 14 | this.camera = new cameras.Perspective(); 15 | this.camera.position.set(25, 25, 50); 16 | 17 | this.controls = new Orbit(this.camera, this.renderer.domElement); 18 | 19 | this.show = false; 20 | 21 | window.addEventListener( 22 | 'click', 23 | () => { 24 | console.log('toggle'); 25 | if (this.show) { 26 | this.mesh.hide(); 27 | this.show = false; 28 | } else { 29 | this.mesh.show(); 30 | this.show = true; 31 | } 32 | }, 33 | false 34 | ); 35 | } 36 | 37 | init() { 38 | this.mesh = new L(); 39 | this.scene.add(this.mesh); 40 | } 41 | 42 | resize(width, height, ratio) { 43 | this.renderer.setSize(width, height); 44 | this.renderer.setRatio(ratio); 45 | } 46 | 47 | pause() {} 48 | 49 | resume() {} 50 | 51 | update() { 52 | // const y = Math.cos(Date.now() / 500) * 0.5; 53 | // this.mesh.container.updateVertices([y], (2 * 3) + 1); // index 0 * xyz + 1 (y) 54 | // this.mesh.updateVertices([y], (3 * 3) + 1); // index 0 * xyz + 1 (y) 55 | // this.mesh.show(); 56 | this.controls.update(); 57 | this.renderer.render(this.scene, this.camera); 58 | } 59 | } 60 | 61 | export { Main }; 62 | -------------------------------------------------------------------------------- /src/basic/index.js: -------------------------------------------------------------------------------- 1 | import Template from '../template'; 2 | 3 | const { Renderer, Scene, cameras, chunks, Model } = lowww.core; 4 | 5 | const { UBO } = chunks; 6 | 7 | class Main extends Template { 8 | setup() { 9 | this.renderer = new Renderer(); 10 | document.body.appendChild(this.renderer.domElement); 11 | 12 | this.scene = new Scene(); 13 | 14 | this.camera = new cameras.Perspective(); 15 | this.camera.position.set(0, 0, 10); 16 | } 17 | 18 | init() { 19 | const vertex = `#version 300 es 20 | in vec3 a_position; 21 | 22 | ${UBO.scene()} 23 | ${UBO.model()} 24 | 25 | void main() { 26 | gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0); 27 | } 28 | `; 29 | 30 | const fragment = `#version 300 es 31 | precision highp float; 32 | precision highp int; 33 | 34 | out vec4 outColor; 35 | 36 | void main() { 37 | outColor = vec4(1.0); 38 | } 39 | `; 40 | 41 | const model = new Model(); 42 | model.setAttribute( 43 | 'a_position', 44 | 'vec3', 45 | new Float32Array([-1, -1, 0, 1, -1, 0, 0, 1, 0]) 46 | ); 47 | model.setShader(vertex, fragment); 48 | this.scene.add(model); 49 | 50 | this.model = model; 51 | } 52 | 53 | resize(width, height, ratio) { 54 | this.renderer.setSize(width, height); 55 | this.renderer.setRatio(ratio); 56 | } 57 | 58 | update() { 59 | this.renderer.render(this.scene, this.camera); 60 | } 61 | } 62 | 63 | export { Main }; 64 | -------------------------------------------------------------------------------- /src/clipping-planes/index.js: -------------------------------------------------------------------------------- 1 | import Template from '../template'; 2 | 3 | const { Renderer, Scene, cameras, Mesh, constants } = lowww.core; 4 | const { Orbit } = lowww.controls; 5 | const { Box } = lowww.geometries; 6 | 7 | const { SIDE } = constants; 8 | 9 | class Main extends Template { 10 | setup() { 11 | this.renderer = new Renderer(); 12 | document.body.appendChild(this.renderer.domElement); 13 | 14 | this.scene = new Scene(); 15 | 16 | this.camera = new cameras.Perspective(); 17 | this.camera.position.set(0, 0, 10); 18 | 19 | this.controls = new Orbit(this.camera, this.renderer.domElement); 20 | } 21 | 22 | init() { 23 | const geometry = new Box(); 24 | this.model = new Mesh({ geometry }); 25 | this.model.side = SIDE.BOTH; 26 | this.scene.add(this.model); 27 | 28 | // global clipping 29 | this.scene.clipping.enable = false; 30 | this.scene.clipping.planes[0] = [0, 1, 0, 0.5]; 31 | 32 | // local clipping 33 | this.model.clipping.enable = true; 34 | this.model.clipping.planes[0] = [1.5, 2.5, 0, 0.5]; 35 | 36 | // gui 37 | this.gui 38 | .add(this.scene.clipping, 'enable') 39 | .name('global clipping') 40 | .onChange(e => (this.scene.clipping.enable = e)); 41 | this.gui 42 | .add(this.model.clipping, 'enable') 43 | .name('local clipping') 44 | .onChange(e => (this.model.clipping.enable = e)); 45 | } 46 | 47 | resize(width, height, ratio) { 48 | this.renderer.setSize(width, height); 49 | this.renderer.setRatio(ratio); 50 | } 51 | 52 | update() { 53 | this.controls.update(); 54 | this.renderer.render(this.scene, this.camera); 55 | } 56 | } 57 | 58 | export { Main }; 59 | -------------------------------------------------------------------------------- /src/geometries/index.js: -------------------------------------------------------------------------------- 1 | import Template from '../template'; 2 | 3 | const { Renderer, Scene, cameras, Mesh } = lowww.core; 4 | const { Orbit } = lowww.controls; 5 | const { 6 | Tetrahedron, 7 | Octahedron, 8 | Hexahedron, 9 | Icosahedron, 10 | Dodecahedron, 11 | Box, 12 | Plane, 13 | Sphere, 14 | Torus, 15 | TorusKnot, 16 | } = lowww.geometries; 17 | 18 | class Main extends Template { 19 | setup() { 20 | this.renderer = new Renderer(); 21 | document.body.appendChild(this.renderer.domElement); 22 | 23 | this.scene = new Scene(); 24 | 25 | this.camera = new cameras.Perspective(); 26 | this.camera.position.set(0, 10, 20); 27 | 28 | this.controls = new Orbit(this.camera, this.renderer.domElement); 29 | } 30 | 31 | init() { 32 | const geometries = [ 33 | Tetrahedron, 34 | Octahedron, 35 | Hexahedron, 36 | Icosahedron, 37 | Dodecahedron, 38 | Box, 39 | Plane, 40 | Sphere, 41 | Torus, 42 | TorusKnot, 43 | ]; 44 | 45 | const radius = 4; 46 | const step = -(2 * Math.PI) / geometries.length; 47 | let angle = 0; 48 | 49 | for (let i = 0; i < geometries.length; i++) { 50 | const geometry = new geometries[i](); 51 | const mesh = new Mesh({ geometry }); 52 | mesh.position.set( 53 | radius * Math.cos(angle), 54 | 0, 55 | radius * Math.sin(angle) 56 | ); 57 | this.scene.add(mesh); 58 | angle += step; 59 | } 60 | } 61 | 62 | resize(width, height, ratio) { 63 | this.renderer.setSize(width, height); 64 | this.renderer.setRatio(ratio); 65 | } 66 | 67 | update() { 68 | this.controls.update(); 69 | this.renderer.render(this.scene, this.camera); 70 | } 71 | } 72 | 73 | export { Main }; 74 | -------------------------------------------------------------------------------- /src/materials/index.js: -------------------------------------------------------------------------------- 1 | import Template from '../template'; 2 | 3 | const { Renderer, Scene, cameras, Mesh, shaders } = lowww.core; 4 | const { Orbit } = lowww.controls; 5 | const { TorusKnot } = lowww.geometries; 6 | 7 | const { Basic, Default, Sem } = shaders; 8 | 9 | class Main extends Template { 10 | setup() { 11 | this.renderer = new Renderer(); 12 | document.body.appendChild(this.renderer.domElement); 13 | 14 | this.scene = new Scene(); 15 | 16 | this.camera = new cameras.Perspective(); 17 | this.camera.position.set(0, 10, 20); 18 | 19 | this.controls = new Orbit(this.camera, this.renderer.domElement); 20 | } 21 | 22 | init() { 23 | const materials = [ 24 | new Basic({ wireframe: true }), 25 | new Basic(), 26 | new Default(), 27 | new Sem({ map: './img/matcap/black-gloss.jpg' }), 28 | ]; 29 | 30 | const geometry = new TorusKnot(); 31 | for (let i = 0; i < materials.length; i++) { 32 | const mesh = new Mesh({ geometry, shader: materials[i] }); 33 | mesh.position.set(3 * i - (3 * (materials.length - 1)) / 2, 0, 0); 34 | this.scene.add(mesh); 35 | } 36 | } 37 | 38 | resize(width, height, ratio) { 39 | this.renderer.setSize(width, height); 40 | this.renderer.setRatio(ratio); 41 | } 42 | 43 | update() { 44 | this.controls.update(); 45 | this.renderer.render(this.scene, this.camera); 46 | } 47 | } 48 | 49 | export { Main }; 50 | -------------------------------------------------------------------------------- /src/modify/index.js: -------------------------------------------------------------------------------- 1 | import Template from '../template'; 2 | 3 | const { Renderer, Scene, cameras, Mesh, constants } = lowww.core; 4 | const { Icosahedron, utils } = lowww.geometries; 5 | 6 | const { SIDE } = constants; 7 | 8 | class Main extends Template { 9 | setup() { 10 | this.renderer = new Renderer(); 11 | document.body.appendChild(this.renderer.domElement); 12 | 13 | this.scene = new Scene(); 14 | this.scene.fog.enable = true; 15 | 16 | this.camera = new cameras.Perspective(); 17 | this.camera.position.set(0, 0, 10); 18 | } 19 | 20 | init() { 21 | this.settings = { 22 | data: ['none', 'modify', 'detach'], 23 | modifier: 'modify', 24 | }; 25 | 26 | this.gui 27 | .add(this.settings, 'modifier', this.settings.data) 28 | .onChange(this.rebuild.bind(this)); 29 | 30 | this.random = []; 31 | for (let i = 0; i < 3000; i++) { 32 | this.random.push(Math.random() * 0.2); 33 | } 34 | 35 | this.original = new Icosahedron({ detail: 2 }); 36 | this.rebuild(); 37 | } 38 | 39 | rebuild() { 40 | if (this.mesh) { 41 | this.scene.remove(this.mesh); 42 | this.mesh = null; 43 | } 44 | 45 | let geometry = this.original; 46 | let vertices = 1; 47 | 48 | if (this.settings.modifier === 'modify') { 49 | geometry = utils.Modify.modify(this.original); 50 | vertices = 3 * 3 * 4; // vertices * XYZ * 4 faces (1 original + 3 generated) 51 | } else if (this.settings.modifier === 'detach') { 52 | geometry = utils.Modify.detach(this.original); 53 | vertices = 3 * 3 * 1; // vertices * XYZ * 1 faces 54 | } 55 | 56 | for (let face = 0; face < geometry.positions.length; face += vertices) { 57 | let r = 1; 58 | if (this.settings.modifier !== 'none') { 59 | r += this.random[face % this.random.length]; 60 | } 61 | 62 | for (let vertice = 0; vertice < vertices; vertice++) { 63 | geometry.positions[face + vertice] *= r; 64 | } 65 | } 66 | 67 | this.mesh = new Mesh({ geometry }); 68 | this.mesh.side = SIDE.BOTH; 69 | 70 | this.scene.add(this.mesh); 71 | } 72 | 73 | resize(width, height, ratio) { 74 | this.renderer.setSize(width, height); 75 | this.renderer.setRatio(ratio); 76 | } 77 | 78 | update() { 79 | // this.mesh.rotation.x += 0.01; 80 | this.mesh.rotation.y += 0.01; 81 | this.renderer.render(this.scene, this.camera); 82 | } 83 | } 84 | 85 | export { Main }; 86 | -------------------------------------------------------------------------------- /src/static/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | background-color: #000; 4 | color: #fff; 5 | font-family: sans-serif; 6 | font-size: 14px; 7 | -moz-osx-font-smoothing: grayscale; 8 | -webkit-font-smoothing: antialiased; 9 | } 10 | 11 | canvas { 12 | display: block; 13 | } 14 | 15 | a { 16 | display: block; 17 | color: #fff; 18 | text-decoration: none; 19 | line-height: 20px; 20 | } 21 | 22 | a:hover { 23 | color: #fff; 24 | } 25 | 26 | a.back, 27 | a.source { 28 | position: fixed; 29 | background-color: rgba(255, 255, 255, 0.05); 30 | padding: 3px 6px; 31 | border-radius: 4px; 32 | font-family: monospace; 33 | font-size: 12px; 34 | } 35 | 36 | a.back:hover, 37 | a.source:hover { 38 | background-color: rgba(255, 255, 255, 0.1); 39 | } 40 | 41 | a.back { 42 | top: 20px; 43 | left: 20px; 44 | } 45 | 46 | a.source { 47 | bottom: 20px; 48 | right: 20px; 49 | } 50 | 51 | a.thumb { 52 | position: relative; 53 | display: inline-block; 54 | border: 1px solid #333; 55 | margin: 10px; 56 | } 57 | a.thumb img { 58 | width: 200px; 59 | height: 150px; 60 | opacity: 1; 61 | transition: all 0.15s ease-in-out; 62 | } 63 | a.thumb p { 64 | position: absolute; 65 | top: 50%; 66 | left: 50%; 67 | opacity: 0; 68 | transform: translateX(-50%) translateY(-100%); 69 | text-align: center; 70 | transition: all 0.15s ease-in-out; 71 | } 72 | 73 | a.thumb:hover img { 74 | opacity: 0.25; 75 | } 76 | 77 | a.thumb:hover p { 78 | top: 50%; 79 | opacity: 1; 80 | } 81 | -------------------------------------------------------------------------------- /src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/favicon.ico -------------------------------------------------------------------------------- /src/static/img/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/facebook.png -------------------------------------------------------------------------------- /src/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/static/img/matcap/black-gloss.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/matcap/black-gloss.jpg -------------------------------------------------------------------------------- /src/static/img/matcap/skin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/matcap/skin.jpg -------------------------------------------------------------------------------- /src/static/img/matcap/world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/matcap/world.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/2d-pattern3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/2d-pattern3.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/2d-pattern3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/2d-pattern3.png -------------------------------------------------------------------------------- /src/static/img/thumbnails/basic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/basic.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/clipping-planes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/clipping-planes.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/geometries.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/geometries.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/instancing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/instancing.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/materials.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/materials.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/modify.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/modify.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/postprocessing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/postprocessing.jpg -------------------------------------------------------------------------------- /src/static/img/thumbnails/render-to-texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/thumbnails/render-to-texture.jpg -------------------------------------------------------------------------------- /src/static/img/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/twitter.png -------------------------------------------------------------------------------- /src/static/img/uv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrevenancio/lowww/a65bac7583b400ffdda8130a98fd24b45e2b06c7/src/static/img/uv.png -------------------------------------------------------------------------------- /src/template.js: -------------------------------------------------------------------------------- 1 | /* global dat */ 2 | class Template { 3 | constructor() { 4 | window.addEventListener('resize', this.handleResize.bind(this), false); 5 | window.addEventListener('focus', this.handleResume.bind(this), false); 6 | window.addEventListener('blur', this.handlePause.bind(this), false); 7 | 8 | this.gui = new dat.GUI(); 9 | this.gui.close(); 10 | 11 | this.setup(); 12 | this.init(); 13 | this.handleResize(); 14 | this.handleResume(); 15 | } 16 | 17 | handleResize() { 18 | this.resize( 19 | window.innerWidth, 20 | window.innerHeight, 21 | window.devicePixelRatio 22 | ); 23 | this.update(); 24 | } 25 | 26 | handleResume() { 27 | this.raf = requestAnimationFrame(this.handleUpdate.bind(this)); 28 | this.resume(); 29 | } 30 | 31 | handlePause() { 32 | cancelAnimationFrame(this.raf); 33 | this.pause(); 34 | } 35 | 36 | handleUpdate() { 37 | this.update(); 38 | this.raf = requestAnimationFrame(this.handleUpdate.bind(this)); 39 | } 40 | 41 | // to be overriden 42 | setup() { 43 | console.warn('please add the setup() method'); 44 | } 45 | init() { 46 | console.warn('please add the init() method'); 47 | } 48 | resize() { 49 | console.warn('please add the resize() method'); 50 | } 51 | pause() {} 52 | resume() {} 53 | update() { 54 | console.warn('please add the update() method'); 55 | } 56 | } 57 | 58 | export default Template; 59 | --------------------------------------------------------------------------------