├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── README.md ├── dist ├── sprite-extend-3d.esm.js ├── sprite-extend-3d.js └── sprite-extend-3d.min.js ├── docs ├── CNAME ├── assets │ ├── compressed │ │ ├── astc-m-y.ktx │ │ ├── etc-m-y.ktx │ │ ├── etc1-m-y.ktx │ │ ├── pvrtc-m-y.ktx │ │ ├── s3tc-m-y.ktx │ │ └── uv.jpg │ ├── croissant.jpg │ ├── croissant.json │ ├── cube │ │ ├── negx.jpg │ │ ├── negy.jpg │ │ ├── negz.jpg │ │ ├── posx.jpg │ │ ├── posy.jpg │ │ └── posz.jpg │ ├── fox.jpg │ ├── fox.json │ ├── girl.jpg │ ├── girl.json │ ├── gltf │ │ └── old_scooter │ │ │ ├── scene.bin │ │ │ └── scene.gltf │ ├── goat.json │ ├── laputa.mp4 │ ├── matcap.jpg │ ├── octopus.jpg │ ├── octopus.json │ └── pbr │ │ ├── black.jpg │ │ ├── car-ext-color.jpg │ │ ├── car-ext-emissive.jpg │ │ ├── car-ext-inner.json │ │ ├── car-ext-normal.jpg │ │ ├── car-ext-opacity.jpg │ │ ├── car-ext-rmo.jpg │ │ ├── car-ext.json │ │ ├── car-int-color.jpg │ │ ├── car-int-normal.jpg │ │ ├── car-int-rmo.jpg │ │ ├── car-int.json │ │ ├── car-shadow.jpg │ │ ├── car-shadow.png │ │ ├── fragment100.glsl │ │ ├── fragment300.glsl │ │ ├── lut.png │ │ ├── vertex100.glsl │ │ ├── vertex300.glsl │ │ ├── waterfall-diffuse-RGBM.png │ │ ├── waterfall-specular-RGBM.png │ │ └── white.jpg ├── basic.html ├── basic2.html ├── basic3.html ├── bindtime.html ├── box.html ├── camera.html ├── compressed-textures.html ├── cube-map.html ├── curves.html ├── d3-earth-2.html ├── d3-earth-3.html ├── d3-earth-4.html ├── d3-earth-5.html ├── d3-earth-6.html ├── d3-earth-7.html ├── d3-earth-plane.html ├── d3-earth.html ├── d3-github-contributions.html ├── d3_bargraph.html ├── flat-shading-matcap.html ├── fox-orbit.html ├── fox.html ├── gltf.html ├── gpgpu-particles.html ├── groups.html ├── high-mesh-count.html ├── instancing.html ├── js │ ├── sprite-extend-3d.esm.js │ ├── sprite-extend-3d.js │ └── spritejs.js ├── lib │ ├── earth.js │ ├── map.js │ ├── missile.js │ ├── missile2.js │ ├── missile3.js │ ├── sky.js │ └── utils.js ├── model.html ├── model2.html ├── normal-maps.html ├── particles.html ├── pbr.html ├── polyline.html ├── polylines.html ├── post-fluid-distortion.html ├── render-to-texture.html ├── rotations.html ├── shadow-maps.html ├── skinning.html ├── skydome.html ├── sort-tansparency.html ├── test.html ├── test2.html ├── test_blend.html ├── text.html ├── textures.html ├── wireframe-shader.html └── wireframe.html ├── examples ├── assets │ ├── compressed │ │ ├── astc-m-y.ktx │ │ ├── etc-m-y.ktx │ │ ├── etc1-m-y.ktx │ │ ├── pvrtc-m-y.ktx │ │ ├── s3tc-m-y.ktx │ │ └── uv.jpg │ ├── croissant.jpg │ ├── croissant.json │ ├── cube │ │ ├── negx.jpg │ │ ├── negy.jpg │ │ ├── negz.jpg │ │ ├── posx.jpg │ │ ├── posy.jpg │ │ └── posz.jpg │ ├── fox.jpg │ ├── fox.json │ ├── girl.jpg │ ├── girl.json │ ├── gltf │ │ └── old_scooter │ │ │ ├── scene.bin │ │ │ └── scene.gltf │ ├── goat.json │ ├── laputa.mp4 │ ├── matcap.jpg │ ├── octopus.jpg │ ├── octopus.json │ └── pbr │ │ ├── black.jpg │ │ ├── car-ext-color.jpg │ │ ├── car-ext-emissive.jpg │ │ ├── car-ext-inner.json │ │ ├── car-ext-normal.jpg │ │ ├── car-ext-opacity.jpg │ │ ├── car-ext-rmo.jpg │ │ ├── car-ext.json │ │ ├── car-int-color.jpg │ │ ├── car-int-normal.jpg │ │ ├── car-int-rmo.jpg │ │ ├── car-int.json │ │ ├── car-shadow.jpg │ │ ├── car-shadow.png │ │ ├── fragment100.glsl │ │ ├── fragment300.glsl │ │ ├── lut.png │ │ ├── vertex100.glsl │ │ ├── vertex300.glsl │ │ ├── waterfall-diffuse-RGBM.png │ │ ├── waterfall-specular-RGBM.png │ │ └── white.jpg ├── basic.html ├── basic2.html ├── basic3.html ├── basic4.html ├── bindtime.html ├── bloom-shading.html ├── bloom.html ├── box.html ├── box_colors.html ├── bump_mapping.html ├── camera.html ├── cannon.html ├── cannon_mousepick.html ├── cannon_pile.html ├── compressed-textures.html ├── cube-map.html ├── curves.html ├── d3-earth-2.html ├── d3-earth-3.html ├── d3-earth-4.html ├── d3-earth-5.html ├── d3-earth-6.html ├── d3-earth-7.html ├── d3-earth-plane.html ├── d3-earth.html ├── d3-github-contributions.html ├── d3_bargraph.html ├── emissive.html ├── flat-shading-matcap.html ├── fox-orbit.html ├── fox.html ├── globe_test.html ├── gltf.html ├── gpgpu-particles.html ├── groups.html ├── high-mesh-count.html ├── instancing.html ├── interleaved.html ├── interleaved2.html ├── js │ ├── cannon.min.js │ └── spritejs.js ├── jupiter.html ├── lib │ ├── earth.js │ ├── map.js │ ├── missile.js │ ├── missile2.js │ ├── missile3.js │ ├── sky.js │ ├── sprite-extend-3d.esm.js │ └── utils.js ├── lights.html ├── model.html ├── model2.html ├── normal-maps.html ├── normal-maps2.html ├── orbit_autoRotate.html ├── particles.html ├── path3d.html ├── pbr.html ├── polyline.html ├── polylines.html ├── post-fluid-distortion.html ├── render-to-texture.html ├── rotations.html ├── shadow-maps.html ├── skinning.html ├── skydome.html ├── sort-tansparency.html ├── sphere_ring.html ├── sphere_test.html ├── sun.html ├── test-esm.html ├── test.html ├── test2.html ├── test_blend.html ├── text.html ├── text2.html ├── textures.html ├── wireframe-shader.html └── wireframe.html ├── lib ├── attribute │ ├── camera.js │ ├── cube.js │ ├── cylinder.js │ ├── mesh3d.js │ ├── node3d.js │ ├── path3d.js │ ├── plane.js │ ├── polyline3d.js │ ├── sphere.js │ └── torus.js ├── helper │ ├── color-attribute.js │ ├── curve.js │ ├── geometry.js │ ├── light.js │ ├── parse-color.js │ ├── shadow.js │ └── texture-loader.js ├── index.js ├── node │ ├── camera.js │ ├── cube.js │ ├── cylinder.js │ ├── group3d.js │ ├── layer3d.js │ ├── mesh3d.js │ ├── node3d.js │ ├── path3d.js │ ├── plane.js │ ├── polyline3d.js │ ├── render-target.js │ ├── skin.js │ ├── sphere.js │ └── torus.js └── shader │ ├── base_geometry.frag │ ├── base_geometry.vert │ ├── dashline.frag │ ├── dashline.vert │ ├── geometry.frag │ ├── geometry.vert │ ├── geometry_normal_map_100.frag │ ├── geometry_normal_map_100.vert │ ├── geometry_normal_map_300.frag │ ├── geometry_normal_map_300.vert │ ├── geometry_with_shadow.frag │ ├── geometry_with_shadow.vert │ ├── index.js │ ├── normal.frag │ ├── normal.vert │ ├── polyline.frag │ ├── polyline.vert │ ├── texture.frag │ ├── texture.vert │ ├── texture_cube.frag │ ├── texture_cube.vert │ ├── texture_normal_map_100.frag │ ├── texture_normal_map_100.vert │ ├── texture_normal_map_300.frag │ ├── texture_normal_map_300.vert │ ├── texture_with_shadow.frag │ └── texture_with_shadow.vert ├── package.json ├── scripts └── compile-shaders.js ├── src ├── attribute │ ├── camera.js │ ├── cube.js │ ├── cylinder.js │ ├── mesh3d.js │ ├── node3d.js │ ├── path3d.js │ ├── plane.js │ ├── polyline3d.js │ ├── sphere.js │ └── torus.js ├── helper │ ├── color-attribute.js │ ├── curve.js │ ├── geometry.js │ ├── light.js │ ├── parse-color.js │ ├── shadow.js │ └── texture-loader.js ├── index.js ├── node │ ├── camera.js │ ├── cube.js │ ├── cylinder.js │ ├── group3d.js │ ├── layer3d.js │ ├── mesh3d.js │ ├── node3d.js │ ├── path3d.js │ ├── plane.js │ ├── polyline3d.js │ ├── render-target.js │ ├── skin.js │ ├── sphere.js │ └── torus.js └── shader │ ├── base_geometry.frag │ ├── base_geometry.vert │ ├── dashline.frag │ ├── dashline.vert │ ├── geometry.frag │ ├── geometry.vert │ ├── geometry_normal_map_100.frag │ ├── geometry_normal_map_100.vert │ ├── geometry_normal_map_300.frag │ ├── geometry_normal_map_300.vert │ ├── geometry_with_shadow.frag │ ├── geometry_with_shadow.vert │ ├── index.js │ ├── normal.frag │ ├── normal.vert │ ├── polyline.frag │ ├── polyline.vert │ ├── texture.frag │ ├── texture.vert │ ├── texture_cube.frag │ ├── texture_cube.vert │ ├── texture_normal_map_100.frag │ ├── texture_normal_map_100.vert │ ├── texture_normal_map_300.frag │ ├── texture_normal_map_300.vert │ ├── texture_with_shadow.frag │ └── texture_with_shadow.vert ├── tools ├── data.obj ├── girl.json └── obj-converter.js ├── typings └── sprite-extend-3d.d.ts └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "chrome": "59" 9 | } 10 | } 11 | ] 12 | ], 13 | "plugins": [ 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/**/*.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const packageConfig = require('./package.json'); 2 | 3 | function toCamelCase(str) { 4 | return str.replace(/-([a-z])/ig, (str, p1) => p1.toUpperCase()); 5 | } 6 | 7 | const libName = toCamelCase(packageConfig.name); 8 | 9 | module.exports = { 10 | globals: { 11 | [libName]: libName, 12 | d3: 'd3', 13 | }, 14 | extends: "eslint-config-sprite", 15 | plugins: ['html'], 16 | rules: { 17 | "complexity": ["warn", 25], 18 | 'import/prefer-default-export': 'off', 19 | "no-unused-vars": 'warn', 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .docz 3 | node_modules 4 | yarn.lock 5 | package-lock.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | benchmark 2 | demos 3 | docs 4 | examples 5 | misc 6 | test 7 | tools 8 | coverage -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sprite extend 3D 2 | 3 | The 3d extension for spritejs. 4 | 5 | ## Usage 6 | 7 | ```html 8 | 9 | 10 | ``` 11 | 12 | ```js 13 | const vertex = /* glsl */ ` 14 | precision highp float; 15 | precision highp int; 16 | 17 | attribute vec2 uv; 18 | attribute vec3 position; 19 | attribute vec3 normal; 20 | 21 | uniform mat4 modelViewMatrix; 22 | uniform mat4 projectionMatrix; 23 | uniform mat3 normalMatrix; 24 | 25 | varying vec2 vUv; 26 | varying vec3 vNormal; 27 | 28 | void main() { 29 | vUv = uv; 30 | vNormal = normalize(normalMatrix * normal); 31 | 32 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 33 | } 34 | `; 35 | 36 | const fragment = /* glsl */ ` 37 | precision highp float; 38 | precision highp int; 39 | 40 | uniform float uTime; 41 | uniform sampler2D tMap; 42 | 43 | varying vec2 vUv; 44 | varying vec3 vNormal; 45 | 46 | void main() { 47 | vec3 normal = normalize(vNormal); 48 | vec3 tex = texture2D(tMap, vUv).rgb; 49 | 50 | vec3 light = normalize(vec3(0.5, 1.0, -0.3)); 51 | float shading = dot(normal, light) * 0.15; 52 | gl_FragColor.rgb = tex + shading; 53 | gl_FragColor.a = 1.0; 54 | } 55 | `; 56 | 57 | const {Scene} = spritejs; 58 | const {Mesh3d} = spritejs.ext3d; 59 | const container = document.getElementById('container'); 60 | const scene = new Scene({ 61 | container, 62 | displayRatio: 2, 63 | }); 64 | const layer = scene.layer3d('fglayer', { 65 | camera: { 66 | fov: 35, 67 | }, 68 | }); 69 | 70 | layer.camera.attributes.pos = [8, 5, 15]; 71 | layer.camera.lookAt([0, 1.5, 0]); 72 | 73 | (async function () { 74 | const texture = await layer.createTexture('https://p3.ssl.qhimg.com/t01d6c6c93fdddf1e42.jpg'); 75 | const program = layer.createProgram({ 76 | vertex, 77 | fragment, 78 | uniforms: { 79 | tMap: {value: texture}, 80 | }, 81 | }); 82 | const model = await layer.loadModel('https://s5.ssl.qhres.com/static/1eb3e9b91a296abd.json'); 83 | const fox = new Mesh3d(program); 84 | fox.setGeometry(model); 85 | layer.append(fox); 86 | fox.animate([ 87 | {rotateY: 0}, 88 | {rotateY: 360}, 89 | ], { 90 | duration: 5000, 91 | iterations: Infinity, 92 | }); 93 | }()); 94 | ``` 95 | 96 | For more details, see [here](https://spritejs.com/#/zh-cn/guide/3d). 97 | 98 | ## Roadmap 99 | 100 | - [x] Shared Geometry 101 | - [x] RenderTarget 102 | - [x] GPGPU 103 | - [x] Polyline 3D 104 | - [x] Cubic Bezier Curve 3D 105 | - [ ] GLTF Loader 106 | - [ ] Flowmap 107 | - [ ] Documentation 108 | - [ ] More examples 109 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | 3d.spritejs.org 2 | -------------------------------------------------------------------------------- /docs/assets/compressed/astc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/compressed/astc-m-y.ktx -------------------------------------------------------------------------------- /docs/assets/compressed/etc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/compressed/etc-m-y.ktx -------------------------------------------------------------------------------- /docs/assets/compressed/etc1-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/compressed/etc1-m-y.ktx -------------------------------------------------------------------------------- /docs/assets/compressed/pvrtc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/compressed/pvrtc-m-y.ktx -------------------------------------------------------------------------------- /docs/assets/compressed/s3tc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/compressed/s3tc-m-y.ktx -------------------------------------------------------------------------------- /docs/assets/compressed/uv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/compressed/uv.jpg -------------------------------------------------------------------------------- /docs/assets/croissant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/croissant.jpg -------------------------------------------------------------------------------- /docs/assets/cube/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/cube/negx.jpg -------------------------------------------------------------------------------- /docs/assets/cube/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/cube/negy.jpg -------------------------------------------------------------------------------- /docs/assets/cube/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/cube/negz.jpg -------------------------------------------------------------------------------- /docs/assets/cube/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/cube/posx.jpg -------------------------------------------------------------------------------- /docs/assets/cube/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/cube/posy.jpg -------------------------------------------------------------------------------- /docs/assets/cube/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/cube/posz.jpg -------------------------------------------------------------------------------- /docs/assets/fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/fox.jpg -------------------------------------------------------------------------------- /docs/assets/girl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/girl.jpg -------------------------------------------------------------------------------- /docs/assets/gltf/old_scooter/scene.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/gltf/old_scooter/scene.bin -------------------------------------------------------------------------------- /docs/assets/laputa.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/laputa.mp4 -------------------------------------------------------------------------------- /docs/assets/matcap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/matcap.jpg -------------------------------------------------------------------------------- /docs/assets/octopus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/octopus.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/black.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-ext-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-ext-color.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-ext-emissive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-ext-emissive.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-ext-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-ext-normal.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-ext-opacity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-ext-opacity.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-ext-rmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-ext-rmo.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-int-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-int-color.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-int-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-int-normal.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-int-rmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-int-rmo.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-shadow.jpg -------------------------------------------------------------------------------- /docs/assets/pbr/car-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/car-shadow.png -------------------------------------------------------------------------------- /docs/assets/pbr/lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/lut.png -------------------------------------------------------------------------------- /docs/assets/pbr/vertex100.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec2 uv; 6 | attribute vec3 normal; 7 | 8 | uniform mat3 normalMatrix; 9 | uniform mat4 modelMatrix; 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 projectionMatrix; 12 | 13 | varying vec2 vUv; 14 | varying vec3 vNormal; 15 | varying vec3 vMPos; 16 | 17 | void main() { 18 | vUv = uv; 19 | vNormal = normalize(normalMatrix * normal); 20 | vMPos = (modelMatrix * vec4(position, 1.0)).xyz; 21 | 22 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 23 | } -------------------------------------------------------------------------------- /docs/assets/pbr/vertex300.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | precision highp int; 4 | 5 | in vec3 position; 6 | in vec2 uv; 7 | in vec3 normal; 8 | 9 | uniform mat3 normalMatrix; 10 | uniform mat4 modelMatrix; 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | out vec2 vUv; 15 | out vec3 vNormal; 16 | out vec3 vMPos; 17 | 18 | void main() { 19 | vUv = uv; 20 | vNormal = normalize(normalMatrix * normal); 21 | vMPos = (modelMatrix * vec4(position, 1.0)).xyz; 22 | 23 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 24 | } -------------------------------------------------------------------------------- /docs/assets/pbr/waterfall-diffuse-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/waterfall-diffuse-RGBM.png -------------------------------------------------------------------------------- /docs/assets/pbr/waterfall-specular-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/waterfall-specular-RGBM.png -------------------------------------------------------------------------------- /docs/assets/pbr/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/docs/assets/pbr/white.jpg -------------------------------------------------------------------------------- /docs/basic2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 104 | 105 | -------------------------------------------------------------------------------- /docs/box.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 87 | 88 | -------------------------------------------------------------------------------- /docs/compressed-textures.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
Compressed Textures.
27 |
28 | 95 | 96 | -------------------------------------------------------------------------------- /docs/cube-map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
Cube Map. Texture by Humus
27 |
28 | 83 | 84 | -------------------------------------------------------------------------------- /docs/curves.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 105 | 106 | -------------------------------------------------------------------------------- /docs/d3-earth-plane.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 88 | 89 | -------------------------------------------------------------------------------- /docs/gltf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 53 | 54 | -------------------------------------------------------------------------------- /docs/lib/earth.js: -------------------------------------------------------------------------------- 1 | const {shaders, Sphere} = spritejs.ext3d; 2 | const defaultEarthFragment = `precision highp float; 3 | precision highp int; 4 | 5 | varying vec3 vNormal; 6 | varying vec4 vColor; 7 | 8 | uniform vec4 directionalLight; //平行光 9 | 10 | uniform sampler2D tMap; 11 | varying vec2 vUv; 12 | 13 | varying float fCos; 14 | 15 | uniform vec4 pointLightColor; // 点光源颜色 16 | uniform vec4 ambientColor; // 环境光 17 | 18 | uniform vec2 uResolution; 19 | 20 | void main() { 21 | vec4 color = vColor; 22 | vec4 texColor = texture2D(tMap, vUv); 23 | vec2 st = gl_FragCoord.xy / uResolution; 24 | 25 | vec3 light = normalize(directionalLight.xyz); 26 | float shading = dot(vNormal, light) * directionalLight.w; 27 | 28 | float alpha = texColor.a; 29 | color.rgb = mix(texColor.rgb, color.rgb, 1.0 - alpha); 30 | color.a = texColor.a + (1.0 - texColor.a) * color.a; 31 | 32 | vec3 diffuse = pointLightColor.rgb * color.rgb * pointLightColor.a * fCos;// 计算点光源漫反射颜色 33 | vec3 ambient = ambientColor.rgb * color.rgb;// 计算环境光反射颜色 34 | 35 | color = vec4(diffuse + ambient, color.a); 36 | 37 | float d = distance(st, vec2(0.5)); 38 | 39 | gl_FragColor.rgb = color.rgb + shading + 0.3 * pow((1.0 - d), 3.0); 40 | gl_FragColor.a = color.a; 41 | } 42 | `; 43 | 44 | const defaultEarthVertex = shaders.GEOMETRY_WITH_TEXTURE.vertex; 45 | 46 | export function createEarth(layer, {vertex = defaultEarthVertex, fragment = defaultEarthFragment, texture, ...attrs} = {}) { 47 | const program = layer.createProgram({ 48 | fragment, 49 | vertex, 50 | // transparent: true, 51 | cullFace: null, 52 | texture, 53 | }); 54 | 55 | attrs = Object.assign({ 56 | widthSegments: 64, 57 | heightSegments: 32, 58 | }, attrs); 59 | 60 | const earth = new Sphere(program, attrs); 61 | layer.append(earth); 62 | 63 | return earth; 64 | } -------------------------------------------------------------------------------- /docs/lib/sky.js: -------------------------------------------------------------------------------- 1 | const vertex = ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec2 uv; 8 | 9 | uniform mat3 normalMatrix; 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 projectionMatrix; 12 | 13 | varying vec2 vUv; 14 | 15 | void main() { 16 | vUv = uv; 17 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 18 | } 19 | `; 20 | 21 | const fragment = ` 22 | precision highp float; 23 | precision highp int; 24 | varying vec2 vUv; 25 | 26 | highp float random(vec2 co) 27 | { 28 | highp float a = 12.9898; 29 | highp float b = 78.233; 30 | highp float c = 43758.5453; 31 | highp float dt= dot(co.xy ,vec2(a,b)); 32 | highp float sn= mod(dt,3.14); 33 | return fract(sin(sn) * c); 34 | } 35 | 36 | // Value Noise by Inigo Quilez - iq/2013 37 | // https://www.shadertoy.com/view/lsf3WH 38 | highp float noise(vec2 st) { 39 | vec2 i = floor(st); 40 | vec2 f = fract(st); 41 | vec2 u = f * f * (3.0 - 2.0 * f); 42 | return mix( mix( random( i + vec2(0.0,0.0) ), 43 | random( i + vec2(1.0,0.0) ), u.x), 44 | mix( random( i + vec2(0.0,1.0) ), 45 | random( i + vec2(1.0,1.0) ), u.x), u.y); 46 | } 47 | 48 | void main() { 49 | gl_FragColor.rgb = vec3(1.0); 50 | gl_FragColor.a = step(0.99, noise(vUv * 1000.0)); 51 | } 52 | `; 53 | 54 | export function createSky(layer) { 55 | const {Sphere} = spritejs.ext3d; 56 | const program = layer.createProgram({ 57 | vertex, 58 | fragment, 59 | transparent: true, 60 | cullFace: null, 61 | }); 62 | const skyBox = new Sphere(program, { 63 | 64 | }); 65 | skyBox.attributes.scale = 50; 66 | layer.append(skyBox); 67 | 68 | return skyBox; 69 | } -------------------------------------------------------------------------------- /docs/lib/utils.js: -------------------------------------------------------------------------------- 1 | const {Vec3} = spritejs.ext3d; 2 | 3 | /** 4 | * 将平面地图坐标转换为球面坐标 5 | * @param {*} u 6 | * @param {*} v 7 | * @param {*} radius 8 | */ 9 | export function project(u, v, radius = 1) { 10 | u /= 1920; 11 | v /= 1000; 12 | const pLength = Math.PI * 2; 13 | const tLength = Math.PI; 14 | const x = -radius * Math.cos(u * pLength) * Math.sin(v * tLength); 15 | const y = radius * Math.cos(v * tLength); 16 | const z = radius * Math.sin(u * pLength) * Math.sin(v * tLength); 17 | return new Vec3(x, y, z); 18 | } 19 | 20 | /** 21 | * 将球面坐标转换为平面地图坐标 22 | * @param {*} x 23 | * @param {*} y 24 | * @param {*} z 25 | * @param {*} radius 26 | */ 27 | export function unproject(x, y, z, radius = 1) { 28 | const pLength = Math.PI * 2; 29 | const tLength = Math.PI; 30 | const v = Math.acos(y / radius) / tLength; // const y = radius * Math.cos(v * tLength); 31 | let u = Math.atan2(-z, x) + Math.PI; // z / x = -1 * Math.tan(u * pLength); 32 | u /= pLength; 33 | return [u * 1920, v * 1000]; 34 | } 35 | 36 | /** 37 | * 将经纬度转换为球面坐标 38 | * @param {*} latitude 39 | * @param {*} longitude 40 | * @param {*} projection 41 | */ 42 | export function latlng_projection(projection, latitude, longitude, radius = 1) { 43 | const [u, v] = projection([longitude, latitude]); 44 | return project(u, v, radius); 45 | } -------------------------------------------------------------------------------- /docs/model2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 97 | 98 | -------------------------------------------------------------------------------- /docs/rotations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 61 | 62 | -------------------------------------------------------------------------------- /docs/skydome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
Skydome. Image credit charlesashaw.
27 |
28 | 61 | 62 | -------------------------------------------------------------------------------- /docs/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 77 | 78 | -------------------------------------------------------------------------------- /docs/test2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 97 | 98 | -------------------------------------------------------------------------------- /docs/test_blend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 22 | 23 | 24 |
25 | 96 | 97 | -------------------------------------------------------------------------------- /docs/text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 61 | 62 | -------------------------------------------------------------------------------- /examples/assets/compressed/astc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/compressed/astc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/etc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/compressed/etc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/etc1-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/compressed/etc1-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/pvrtc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/compressed/pvrtc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/s3tc-m-y.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/compressed/s3tc-m-y.ktx -------------------------------------------------------------------------------- /examples/assets/compressed/uv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/compressed/uv.jpg -------------------------------------------------------------------------------- /examples/assets/croissant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/croissant.jpg -------------------------------------------------------------------------------- /examples/assets/cube/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/cube/negx.jpg -------------------------------------------------------------------------------- /examples/assets/cube/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/cube/negy.jpg -------------------------------------------------------------------------------- /examples/assets/cube/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/cube/negz.jpg -------------------------------------------------------------------------------- /examples/assets/cube/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/cube/posx.jpg -------------------------------------------------------------------------------- /examples/assets/cube/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/cube/posy.jpg -------------------------------------------------------------------------------- /examples/assets/cube/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/cube/posz.jpg -------------------------------------------------------------------------------- /examples/assets/fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/fox.jpg -------------------------------------------------------------------------------- /examples/assets/girl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/girl.jpg -------------------------------------------------------------------------------- /examples/assets/gltf/old_scooter/scene.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/gltf/old_scooter/scene.bin -------------------------------------------------------------------------------- /examples/assets/laputa.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/laputa.mp4 -------------------------------------------------------------------------------- /examples/assets/matcap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/matcap.jpg -------------------------------------------------------------------------------- /examples/assets/octopus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/octopus.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/black.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-ext-color.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-emissive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-ext-emissive.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-ext-normal.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-opacity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-ext-opacity.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-ext-rmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-ext-rmo.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-int-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-int-color.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-int-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-int-normal.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-int-rmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-int-rmo.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-shadow.jpg -------------------------------------------------------------------------------- /examples/assets/pbr/car-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/car-shadow.png -------------------------------------------------------------------------------- /examples/assets/pbr/lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/lut.png -------------------------------------------------------------------------------- /examples/assets/pbr/vertex100.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec2 uv; 6 | attribute vec3 normal; 7 | 8 | uniform mat3 normalMatrix; 9 | uniform mat4 modelMatrix; 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 projectionMatrix; 12 | 13 | varying vec2 vUv; 14 | varying vec3 vNormal; 15 | varying vec3 vMPos; 16 | 17 | void main() { 18 | vUv = uv; 19 | vNormal = normalize(normalMatrix * normal); 20 | vMPos = (modelMatrix * vec4(position, 1.0)).xyz; 21 | 22 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 23 | } -------------------------------------------------------------------------------- /examples/assets/pbr/vertex300.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | precision highp int; 4 | 5 | in vec3 position; 6 | in vec2 uv; 7 | in vec3 normal; 8 | 9 | uniform mat3 normalMatrix; 10 | uniform mat4 modelMatrix; 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | out vec2 vUv; 15 | out vec3 vNormal; 16 | out vec3 vMPos; 17 | 18 | void main() { 19 | vUv = uv; 20 | vNormal = normalize(normalMatrix * normal); 21 | vMPos = (modelMatrix * vec4(position, 1.0)).xyz; 22 | 23 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 24 | } -------------------------------------------------------------------------------- /examples/assets/pbr/waterfall-diffuse-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/waterfall-diffuse-RGBM.png -------------------------------------------------------------------------------- /examples/assets/pbr/waterfall-specular-RGBM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/waterfall-specular-RGBM.png -------------------------------------------------------------------------------- /examples/assets/pbr/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/examples/assets/pbr/white.jpg -------------------------------------------------------------------------------- /examples/basic4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 69 | 70 | -------------------------------------------------------------------------------- /examples/box.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 87 | 88 | -------------------------------------------------------------------------------- /examples/box_colors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 91 | 92 | -------------------------------------------------------------------------------- /examples/compressed-textures.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
Compressed Textures.
27 |
28 | 95 | 96 | -------------------------------------------------------------------------------- /examples/cube-map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
Cube Map. Texture by Humus
27 |
28 | 83 | 84 | -------------------------------------------------------------------------------- /examples/curves.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 105 | 106 | -------------------------------------------------------------------------------- /examples/d3-earth-plane.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 95 | 96 | -------------------------------------------------------------------------------- /examples/emissive.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 99 | 100 | -------------------------------------------------------------------------------- /examples/gltf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 53 | 54 | -------------------------------------------------------------------------------- /examples/interleaved.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 15 | 16 | 17 |
18 | 117 | 118 | -------------------------------------------------------------------------------- /examples/interleaved2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 15 | 16 | 17 |
18 | 138 | 139 | -------------------------------------------------------------------------------- /examples/lib/sky.js: -------------------------------------------------------------------------------- 1 | const vertex = ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec2 uv; 8 | 9 | uniform mat3 normalMatrix; 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 projectionMatrix; 12 | 13 | varying vec2 vUv; 14 | 15 | void main() { 16 | vUv = uv; 17 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 18 | } 19 | `; 20 | 21 | const fragment = ` 22 | precision highp float; 23 | precision highp int; 24 | varying vec2 vUv; 25 | 26 | highp float random(vec2 co) 27 | { 28 | highp float a = 12.9898; 29 | highp float b = 78.233; 30 | highp float c = 43758.5453; 31 | highp float dt= dot(co.xy ,vec2(a,b)); 32 | highp float sn= mod(dt,3.14); 33 | return fract(sin(sn) * c); 34 | } 35 | 36 | // Value Noise by Inigo Quilez - iq/2013 37 | // https://www.shadertoy.com/view/lsf3WH 38 | highp float noise(vec2 st) { 39 | vec2 i = floor(st); 40 | vec2 f = fract(st); 41 | vec2 u = f * f * (3.0 - 2.0 * f); 42 | return mix( mix( random( i + vec2(0.0,0.0) ), 43 | random( i + vec2(1.0,0.0) ), u.x), 44 | mix( random( i + vec2(0.0,1.0) ), 45 | random( i + vec2(1.0,1.0) ), u.x), u.y); 46 | } 47 | 48 | void main() { 49 | gl_FragColor.rgb = vec3(1.0); 50 | gl_FragColor.a = step(0.99, noise(vUv * 1000.0)); 51 | } 52 | `; 53 | 54 | export function createSky(layer) { 55 | const {Sphere} = spritejs.ext3d; 56 | const program = layer.createProgram({ 57 | vertex, 58 | fragment, 59 | transparent: true, 60 | cullFace: null, 61 | }); 62 | const skyBox = new Sphere(program, { 63 | 64 | }); 65 | skyBox.attributes.scale = 50; 66 | layer.append(skyBox); 67 | 68 | return skyBox; 69 | } -------------------------------------------------------------------------------- /examples/lib/utils.js: -------------------------------------------------------------------------------- 1 | const {Vec3} = spritejs.ext3d; 2 | 3 | /** 4 | * 将平面地图坐标转换为球面坐标 5 | * @param {*} u 6 | * @param {*} v 7 | * @param {*} radius 8 | */ 9 | export function project(u, v, radius = 1) { 10 | u /= 1920; 11 | v /= 1000; 12 | const pLength = Math.PI * 2; 13 | const tLength = Math.PI; 14 | const x = -radius * Math.cos(u * pLength) * Math.sin(v * tLength); 15 | const y = radius * Math.cos(v * tLength); 16 | const z = radius * Math.sin(u * pLength) * Math.sin(v * tLength); 17 | return new Vec3(x, y, z); 18 | } 19 | 20 | /** 21 | * 将球面坐标转换为平面地图坐标 22 | * @param {*} x 23 | * @param {*} y 24 | * @param {*} z 25 | * @param {*} radius 26 | */ 27 | export function unproject(x, y, z, radius = 1) { 28 | const pLength = Math.PI * 2; 29 | const tLength = Math.PI; 30 | const v = Math.acos(y / radius) / tLength; // const y = radius * Math.cos(v * tLength); 31 | let u = Math.atan2(-z, x) + Math.PI; // z / x = -1 * Math.tan(u * pLength); 32 | u /= pLength; 33 | return [u * 1920, v * 1000]; 34 | } 35 | 36 | /** 37 | * 将经纬度转换为球面坐标 38 | * @param {*} latitude 39 | * @param {*} longitude 40 | * @param {*} projection 41 | */ 42 | export function latlng_projection(projection, latitude, longitude, radius = 1) { 43 | const [u, v] = projection([longitude, latitude]); 44 | return project(u, v, radius); 45 | } -------------------------------------------------------------------------------- /examples/lights.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 78 | 79 | -------------------------------------------------------------------------------- /examples/model2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 97 | 98 | -------------------------------------------------------------------------------- /examples/normal-maps2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 86 | 87 | -------------------------------------------------------------------------------- /examples/orbit_autoRotate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 54 | 55 | -------------------------------------------------------------------------------- /examples/path3d.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 109 | 110 | -------------------------------------------------------------------------------- /examples/rotations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 61 | 62 | -------------------------------------------------------------------------------- /examples/skydome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
Skydome. Image credit charlesashaw.
27 |
28 | 61 | 62 | -------------------------------------------------------------------------------- /examples/sphere_test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 80 | 81 | -------------------------------------------------------------------------------- /examples/test-esm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ESM 7 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /examples/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 81 | 82 | -------------------------------------------------------------------------------- /examples/test2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 97 | 98 | -------------------------------------------------------------------------------- /examples/test_blend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 22 | 23 | 24 |
25 | 96 | 97 | -------------------------------------------------------------------------------- /examples/text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 70 | 71 | -------------------------------------------------------------------------------- /examples/text2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 24 | 25 | 26 |
27 | 84 | 85 | -------------------------------------------------------------------------------- /lib/attribute/camera.js: -------------------------------------------------------------------------------- 1 | import Node3dAttr from './node3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class GameraAttr extends Node3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | near: 0.1, 10 | far: 100, 11 | fov: 45, 12 | aspect: 1, 13 | left: undefined, 14 | right: undefined, 15 | bottom: undefined, 16 | top: undefined, 17 | zoom: 1, 18 | mode: 'perspective' // perspective - 透视相机, orthographic - 正交投影相机 19 | 20 | }); 21 | } 22 | 23 | get near() { 24 | return this[getAttribute]('near'); 25 | } 26 | 27 | set near(value) { 28 | this[setAttribute]('near', value); 29 | } 30 | 31 | get far() { 32 | return this[getAttribute]('far'); 33 | } 34 | 35 | set far(value) { 36 | this[setAttribute]('far', value); 37 | } 38 | 39 | get fov() { 40 | return this[getAttribute]('fov'); 41 | } 42 | 43 | set fov(value) { 44 | this[setAttribute]('fov', value); 45 | } 46 | 47 | get aspect() { 48 | return this[getAttribute]('aspect'); 49 | } 50 | 51 | set aspect(value) { 52 | this[setAttribute]('aspect', value); 53 | } 54 | 55 | get left() { 56 | return this[getAttribute]('left'); 57 | } 58 | 59 | set left(value) { 60 | this[setAttribute]('left', value); 61 | } 62 | 63 | get right() { 64 | return this[getAttribute]('right'); 65 | } 66 | 67 | set right(value) { 68 | this[setAttribute]('right', value); 69 | } 70 | 71 | get top() { 72 | return this[getAttribute]('top'); 73 | } 74 | 75 | set top(value) { 76 | this[setAttribute]('top', value); 77 | } 78 | 79 | get bottom() { 80 | return this[getAttribute]('bottom'); 81 | } 82 | 83 | set bottom(value) { 84 | this[setAttribute]('bottom', value); 85 | } 86 | 87 | get zoom() { 88 | return this[getAttribute]('zoom'); 89 | } 90 | 91 | set zoom(value) { 92 | this[setAttribute]('zoom', value); 93 | } 94 | 95 | get mode() { 96 | return this[getAttribute]('mode'); 97 | } 98 | 99 | set mode(value) { 100 | if (value && value !== 'perspective' && value !== 'orthographic') { 101 | throw new TypeError('Invalid camera mode.'); 102 | } 103 | 104 | this[setAttribute]('mode', value); 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /lib/attribute/cube.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class CubeAttr extends Mesh3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | width: 1, 10 | height: 1, 11 | depth: 1, 12 | 13 | /* size */ 14 | widthSegments: 1, 15 | heightSegments: 1, 16 | depthSegments: 1, 17 | 18 | /* override */ 19 | colorDivisor: 4 20 | }); 21 | } 22 | 23 | get width() { 24 | return this[getAttribute]('width'); 25 | } 26 | 27 | set width(value) { 28 | this[setAttribute]('width', value); 29 | } 30 | 31 | get height() { 32 | return this[getAttribute]('height'); 33 | } 34 | 35 | set height(value) { 36 | this[setAttribute]('height', value); 37 | } 38 | 39 | get size() { 40 | return [this.width, this.height, this.depth]; 41 | } 42 | 43 | set size(value) { 44 | if (!Array.isArray(value)) value = [value, value, value]; 45 | this.width = value[0]; 46 | this.height = value[1]; 47 | this.depth = value[2]; 48 | } 49 | 50 | get depth() { 51 | return this[getAttribute]('depth'); 52 | } 53 | 54 | set depth(value) { 55 | this[setAttribute]('depth', value); 56 | } 57 | 58 | get widthSegments() { 59 | return this[getAttribute]('widthSegments'); 60 | } 61 | 62 | set widthSegments(value) { 63 | this[setAttribute]('widthSegments', value); 64 | } 65 | 66 | get heightSegments() { 67 | return this[getAttribute]('heightSegments'); 68 | } 69 | 70 | set heightSegments(value) { 71 | this[setAttribute]('heightSegments', value); 72 | } 73 | 74 | get depthSegments() { 75 | return this[getAttribute]('depthSegments'); 76 | } 77 | 78 | set depthSegments(value) { 79 | this[setAttribute]('depthSegments', value); 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /lib/attribute/cylinder.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class CylinderAttr extends Mesh3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | radiusTop: 0.5, 10 | radiusBottom: 0.5, 11 | 12 | /* radius */ 13 | height: 1, 14 | radialSegments: 16, 15 | heightSegments: 1, 16 | openEnded: false, 17 | thetaStart: 0, 18 | thetaLength: Math.PI * 2 19 | }); 20 | } 21 | 22 | get radiusTop() { 23 | return this[getAttribute]('radiusTop'); 24 | } 25 | 26 | set radiusTop(value) { 27 | this[setAttribute]('radiusTop', value); 28 | } 29 | 30 | get radiusBottom() { 31 | return this[getAttribute]('radiusBottom'); 32 | } 33 | 34 | set radiusBottom(value) { 35 | this[setAttribute]('radiusBottom', value); 36 | } 37 | 38 | get radius() { 39 | return [this.radiusTop, this.radiusBottom]; 40 | } 41 | 42 | set radius(value) { 43 | if (!Array.isArray(value)) value = [value, value]; 44 | this.radiusTop = value[0]; 45 | this.radiusBottom = value[1]; 46 | } 47 | 48 | get height() { 49 | return this[getAttribute]('height'); 50 | } 51 | 52 | set height(value) { 53 | this[setAttribute]('height', value); 54 | } 55 | 56 | get radialSegments() { 57 | return this[getAttribute]('radialSegments'); 58 | } 59 | 60 | set radialSegments(value) { 61 | this[setAttribute]('radialSegments', value); 62 | } 63 | 64 | get heightSegments() { 65 | return this[getAttribute]('heightSegments'); 66 | } 67 | 68 | set heightSegments(value) { 69 | this[setAttribute]('heightSegments', value); 70 | } 71 | 72 | get openEnded() { 73 | return this[getAttribute]('openEnded'); 74 | } 75 | 76 | set openEnded(value) { 77 | this[setAttribute]('openEnded', value); 78 | } 79 | 80 | get thetaStart() { 81 | return this[getAttribute]('thetaStart'); 82 | } 83 | 84 | set thetaStart(value) { 85 | this[setAttribute]('thetaStart', value); 86 | } 87 | 88 | get thetaLength() { 89 | return this[getAttribute]('thetaLength'); 90 | } 91 | 92 | set thetaLength(value) { 93 | this[setAttribute]('thetaLength', value); 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /lib/attribute/mesh3d.js: -------------------------------------------------------------------------------- 1 | import { Color } from 'spritejs'; 2 | import Node3dAttr from './node3d'; 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | export default class Mesh3dAttr extends Node3dAttr { 7 | constructor(subject) { 8 | super(subject); 9 | this[setDefault]({ 10 | mode: 'TRIANGLES', 11 | // POINTS, LINES, LINE_LOOP, LINE_STRIP, TRIANGLES 12 | colors: [0.5, 0.5, 0.5, 1], 13 | colorDivisor: 3, 14 | raycast: 'box' // box sphere none 15 | 16 | }); 17 | } 18 | 19 | get colors() { 20 | return this[getAttribute]('colors'); 21 | } 22 | 23 | set colors(value) { 24 | if (typeof value === 'string') { 25 | value = value.replace(/\s*,\s*/g, ','); 26 | let colors = value.split(/\s+/g); 27 | colors = colors.map(c => { 28 | return new Color(c); 29 | }); 30 | value = colors.reduce((a, b) => [...a, ...b]); 31 | } else if (Array.isArray(value)) { 32 | if (typeof value[0] === 'string') { 33 | value = value.reduce((a, b) => { 34 | a.push(...new Color(b)); 35 | return a; 36 | }, []); 37 | } else if (Array.isArray(value[0])) { 38 | value = value.reduce((a, b) => [...a, ...b]); 39 | } 40 | } 41 | 42 | this[setAttribute]('colors', value); 43 | } 44 | 45 | get colorDivisor() { 46 | return this[getAttribute]('colorDivisor'); 47 | } 48 | 49 | set colorDivisor(value) { 50 | this[setAttribute]('colorDivisor', value); 51 | } 52 | 53 | get mode() { 54 | return this[getAttribute]('mode'); 55 | } 56 | 57 | set mode(value) { 58 | if (typeof value === 'number' && value >= 0 && value < 7) { 59 | value = ['POINTS', 'LINES', 'LINE_LOOP', 'LINE_STRIP', 'TRIANGLES', 'TRIANGLE_STRIP', 'TRIANGLE_FAN'][value]; 60 | } 61 | 62 | if (value && value !== 'TRIANGLES' && value !== 'POINTS' && value !== 'LINES' && value !== 'LINE_LOOP' && value !== 'LINE_STRIP' && value !== 'TRIANGLE_STRIP' && value !== 'TRIANGLE_FAN') { 63 | throw new TypeError('Invalid mode value.'); 64 | } 65 | 66 | this[setAttribute]('mode', value); 67 | } 68 | 69 | get raycast() { 70 | return this[getAttribute]('raycast'); 71 | } 72 | 73 | set raycast(value) { 74 | this[setAttribute]('raycast', value); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /lib/attribute/plane.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class PlaneAttr extends Mesh3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | width: 1, 10 | height: 1, 11 | widthSegments: 1, 12 | heightSegments: 1 13 | }); 14 | } 15 | 16 | get width() { 17 | return this[getAttribute]('width'); 18 | } 19 | 20 | set width(value) { 21 | this[setAttribute]('width', value); 22 | } 23 | 24 | get height() { 25 | return this[getAttribute]('height'); 26 | } 27 | 28 | set height(value) { 29 | this[setAttribute]('height', value); 30 | } 31 | 32 | get widthSegments() { 33 | return this[getAttribute]('widthSegments'); 34 | } 35 | 36 | set widthSegments(value) { 37 | this[setAttribute]('widthSegments', value); 38 | } 39 | 40 | get heightSegments() { 41 | return this[getAttribute]('heightSegments'); 42 | } 43 | 44 | set heightSegments(value) { 45 | this[setAttribute]('heightSegments', value); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /lib/attribute/polyline3d.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class PolylineAttr extends Mesh3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | points: [], 10 | raycast: 'none' 11 | }); 12 | } 13 | 14 | get points() { 15 | return this[getAttribute]('points'); 16 | } 17 | 18 | set points(value) { 19 | if (Array.isArray(value)) { 20 | value = value.reduce((a, b) => { 21 | if (Array.isArray(b)) { 22 | return [...a, ...b]; 23 | } 24 | 25 | return [...a, b]; 26 | }, []); 27 | } // if(value) { // 要去掉重复的点 28 | // if(value.length % 3) throw new Error('Invalid points set'); 29 | // const points = [value[0], value[1], value[2]]; 30 | // for(let i = 3; i < value.length; i += 3) { 31 | // if(value[i] !== value[i - 3] || value[i + 1] !== value[i - 2] || value[i + 2] !== value[i - 1]) { 32 | // points.push(value[i], value[i + 1], value[i + 2]); 33 | // } 34 | // } 35 | // value = points; 36 | // } 37 | 38 | 39 | this[setAttribute]('points', value); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /lib/attribute/sphere.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class SphereAttr extends Mesh3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | radius: 0.5, 10 | widthSegments: 32, 11 | heightSegments: 16, 12 | phiStart: 0, 13 | phiLength: Math.PI * 2, 14 | thetaStart: 0, 15 | thetaLength: Math.PI, 16 | raycast: 'sphere' 17 | }); 18 | } 19 | 20 | get radius() { 21 | return this[getAttribute]('radius'); 22 | } 23 | 24 | set radius(value) { 25 | this[setAttribute]('radius', value); 26 | } 27 | 28 | get widthSegments() { 29 | return this[getAttribute]('widthSegments'); 30 | } 31 | 32 | set widthSegments(value) { 33 | this[setAttribute]('widthSegments', value); 34 | } 35 | 36 | get heightSegments() { 37 | return this[getAttribute]('heightSegments'); 38 | } 39 | 40 | set heightSegments(value) { 41 | this[setAttribute]('heightSegments', value); 42 | } 43 | 44 | get phiStart() { 45 | return this[getAttribute]('phiStart'); 46 | } 47 | 48 | set phiStart(value) { 49 | this[setAttribute]('phiStart', value); 50 | } 51 | 52 | get phiLength() { 53 | return this[getAttribute]('phiLength'); 54 | } 55 | 56 | set phiLength(value) { 57 | this[setAttribute]('phiLength', value); 58 | } 59 | 60 | get thetaStart() { 61 | return this[getAttribute]('thetaStart'); 62 | } 63 | 64 | set thetaStart(value) { 65 | this[setAttribute]('thetaStart', value); 66 | } 67 | 68 | get thetaLength() { 69 | return this[getAttribute]('thetaLength'); 70 | } 71 | 72 | set thetaLength(value) { 73 | this[setAttribute]('thetaLength', value); 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /lib/attribute/torus.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | const setAttribute = Symbol.for('spritejs_setAttribute'); 3 | const getAttribute = Symbol.for('spritejs_getAttribute'); 4 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 5 | export default class TorusAttr extends Mesh3dAttr { 6 | constructor(subject) { 7 | super(subject); 8 | this[setDefault]({ 9 | radius: 0.5, 10 | tube: 0.2, 11 | radialSegments: 8, 12 | tubularSegments: 6, 13 | arc: Math.PI * 2 14 | }); 15 | } 16 | 17 | get radius() { 18 | return this[getAttribute]('radius'); 19 | } 20 | 21 | set radius(value) { 22 | this[setAttribute]('radius', value); 23 | } 24 | 25 | get tube() { 26 | return this[getAttribute]('tube'); 27 | } 28 | 29 | set tube(value) { 30 | this[setAttribute]('tube', value); 31 | } 32 | 33 | get radialSegments() { 34 | return this[getAttribute]('radialSegments'); 35 | } 36 | 37 | set radialSegments(value) { 38 | this[setAttribute]('radialSegments', value); 39 | } 40 | 41 | get tubularSegments() { 42 | return this[getAttribute]('tubularSegments'); 43 | } 44 | 45 | set tubularSegments(value) { 46 | this[setAttribute]('tubularSegments', value); 47 | } 48 | 49 | get arc() { 50 | return this[getAttribute]('arc'); 51 | } 52 | 53 | set arc(value) { 54 | this[setAttribute]('arc', value); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /lib/helper/color-attribute.js: -------------------------------------------------------------------------------- 1 | export function colorAttribute(node, geometry) { 2 | const updateColor = geometry.attributes.color; 3 | const positions = geometry.attributes.position.data; 4 | const size = geometry.attributes.position.size || 3; 5 | const len = positions.length / size; 6 | const color = updateColor ? updateColor.data : new Float32Array(4 * len); 7 | const colors = node.attributes.colors; 8 | const colorLen = colors.length / 4; 9 | const colorDivisor = node.attributes.colorDivisor; 10 | 11 | for (let i = 0; i < len; i++) { 12 | // const color = colors 13 | const idx = Math.floor(i / colorDivisor) % colorLen; 14 | color[4 * i] = colors[idx * 4]; 15 | color[4 * i + 1] = colors[idx * 4 + 1]; 16 | color[4 * i + 2] = colors[idx * 4 + 2]; 17 | color[4 * i + 3] = colors[idx * 4 + 3]; 18 | } 19 | 20 | if (updateColor) updateColor.needsUpdate = true; 21 | return { 22 | size: 4, 23 | data: color 24 | }; 25 | } -------------------------------------------------------------------------------- /lib/helper/curve.js: -------------------------------------------------------------------------------- 1 | import { Curve as _Curve, Vec3 } from 'ogl'; 2 | export default class Curve extends _Curve { 3 | constructor({ 4 | points, 5 | divisions, 6 | type 7 | } = {}) { 8 | if (Array.isArray(points) && points[0] && !(points[0] instanceof Vec3)) { 9 | points = points.map(p => new Vec3().copy(p)); 10 | } 11 | 12 | super({ 13 | points, 14 | divisions, 15 | type 16 | }); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /lib/helper/light.js: -------------------------------------------------------------------------------- 1 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2 | 3 | import { parseColor } from './parse-color'; 4 | export default class Light { 5 | constructor({ 6 | angle, 7 | direction, 8 | position, 9 | blur = 0, 10 | color = [1, 1, 1, 1], 11 | decay = [0, 0, 1] 12 | } = {}) { 13 | this.angle = angle; 14 | this.blur = blur; 15 | this.color = color ? parseColor(color) : undefined; 16 | this.decay = decay; 17 | this.direction = direction; 18 | this.position = position; 19 | 20 | if (this.position && this.direction && this.angle == null) { 21 | this.angle = Math.PI / 3; 22 | } 23 | } 24 | 25 | get type() { 26 | if (this.position && this.direction) return Light.SPOT_LIGHT; 27 | if (this.position) return Light.POINT_LIGHT; 28 | if (this.direction) return Light.DIRECTIONAL_LIGHT; 29 | throw new Error('unknown light'); 30 | } 31 | 32 | } 33 | 34 | _defineProperty(Light, "DIRECTIONAL_LIGHT", 0); 35 | 36 | _defineProperty(Light, "POINT_LIGHT", 1); 37 | 38 | _defineProperty(Light, "SPOT_LIGHT", 2); -------------------------------------------------------------------------------- /lib/helper/parse-color.js: -------------------------------------------------------------------------------- 1 | import { Color } from 'spritejs'; 2 | export function parseColor(colors) { 3 | if (Array.isArray(colors)) { 4 | return colors.map(c => { 5 | if (typeof c === 'string') { 6 | return new Color(c); 7 | } 8 | 9 | return c; 10 | }); 11 | } 12 | 13 | return typeof colors === 'string' ? new Color(colors) : colors; 14 | } -------------------------------------------------------------------------------- /lib/helper/shadow.js: -------------------------------------------------------------------------------- 1 | import { Shadow as _Shadow } from 'ogl'; // https://github.com/oframe/ogl/blob/master/src/extras/Shadow.js 2 | 3 | export default class Shadow extends _Shadow { 4 | async add(node, opts = {}) { 5 | await node.model; 6 | opts.mesh = node.body; 7 | node.addEventListener('updatemesh', evt => { 8 | const oldMesh = evt.detail.oldMesh; 9 | this.castMeshes = this.castMeshes.filter(mesh => mesh !== oldMesh); 10 | this.add(node, opts); 11 | }); 12 | super.add(opts); 13 | } 14 | 15 | remove(node) { 16 | const mesh = node.body; 17 | 18 | if (mesh) { 19 | const idx = this.castMeshes.indexOf(mesh); 20 | 21 | if (idx >= 0) { 22 | this.castMeshes.splice(idx, 1); 23 | return true; 24 | } 25 | } 26 | 27 | return false; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /lib/helper/texture-loader.js: -------------------------------------------------------------------------------- 1 | import { TextureLoader as _TextureLoader } from 'ogl'; 2 | export default class TextureLoader { 3 | static load(layer, opts) { 4 | const texture = _TextureLoader.load(layer.gl, opts); 5 | 6 | if (texture && texture.loaded && texture.loaded.then) { 7 | // load loadKTX 8 | texture.loaded.then(() => { 9 | layer.forceUpdate(); 10 | }); 11 | } else if (texture && texture.then) { 12 | // load Image 13 | texture.then(() => { 14 | layer.forceUpdate(); 15 | }); 16 | } 17 | 18 | return texture; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | import { Raycast, GPGPU, Vec2, Vec3, Vec4, Mat3, Mat4, Quat, Euler, RenderTarget as FrameBuffer } from 'ogl'; 2 | import Layer3d from './node/layer3d'; 3 | import Mesh3d from './node/mesh3d'; 4 | import Skin from './node/skin'; 5 | import Sphere from './node/sphere'; 6 | import Torus from './node/torus'; 7 | import Camera from './node/camera'; 8 | import Cube from './node/cube'; 9 | import Curve from './helper/curve'; 10 | import Plane from './node/plane'; 11 | import Polyline3d from './node/polyline3d'; 12 | import Cylinder from './node/cylinder'; 13 | import Path3d from './node/path3d'; 14 | import Group3d from './node/group3d'; 15 | import RenderTarget from './node/render-target'; 16 | import Shadow from './helper/shadow'; 17 | import TextureLoader from './helper/texture-loader'; 18 | import Geometry from './helper/geometry'; 19 | import Light from './helper/light'; 20 | import * as shaders from './shader'; 21 | export { Layer3d, Sphere, Torus, Plane, Polyline3d, Camera, Cube, Cylinder, Path3d, Mesh3d, Skin, Group3d, RenderTarget, Shadow, Light, TextureLoader, Geometry, Curve, shaders, Vec2, Vec3, Vec4, Mat3, Mat4, Quat, Euler, GPGPU, Raycast, FrameBuffer }; -------------------------------------------------------------------------------- /lib/node/cube.js: -------------------------------------------------------------------------------- 1 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2 | 3 | import { registerNode } from 'spritejs'; 4 | import { Box } from 'ogl'; 5 | import Mesh3d from './mesh3d'; 6 | import CubeAttr from '../attribute/cube'; 7 | export default class Cube extends Mesh3d { 8 | /* override */ 9 | onPropertyChange(key, newValue, oldValue) { 10 | super.onPropertyChange(key, newValue, oldValue); 11 | 12 | if (key === 'width' || key === 'height' || key === 'depth' || key === 'widthSegments' || key === 'heightSegments' || key === 'depthSegments') { 13 | if (newValue !== oldValue) { 14 | this.updateMesh(); 15 | } 16 | } 17 | } 18 | /* override */ 19 | 20 | 21 | remesh() { 22 | const gl = this.program.gl; 23 | const { 24 | width, 25 | height, 26 | depth, 27 | widthSegments, 28 | heightSegments, 29 | depthSegments 30 | } = this.attributes; 31 | const geometry = new Box(gl, { 32 | width, 33 | height, 34 | depth, 35 | widthSegments, 36 | heightSegments, 37 | depthSegments 38 | }); 39 | this.setGeometry(geometry); 40 | } 41 | 42 | } 43 | 44 | _defineProperty(Cube, "Attr", CubeAttr); 45 | 46 | registerNode(Cube, 'cube'); -------------------------------------------------------------------------------- /lib/node/cylinder.js: -------------------------------------------------------------------------------- 1 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2 | 3 | import { registerNode } from 'spritejs'; 4 | import { Cylinder as _Cylinder } from 'ogl'; 5 | import CylinderAttr from '../attribute/cylinder'; 6 | import Mesh3d from './mesh3d'; 7 | export default class Cylinder extends Mesh3d { 8 | /* override */ 9 | onPropertyChange(key, newValue, oldValue) { 10 | super.onPropertyChange(key, newValue, oldValue); 11 | 12 | if (key === 'radiusTop' || key === 'radiusBottom' || key === 'height' || key === 'radialSegments' || key === 'heightSegments' || key === 'openEnded' || key === 'thetaStart' || key === 'thetaLength') { 13 | if (newValue !== oldValue) { 14 | this.updateMesh(); 15 | } 16 | } 17 | } 18 | /* override */ 19 | 20 | 21 | remesh() { 22 | const gl = this.program.gl; 23 | const { 24 | radiusTop, 25 | radiusBottom, 26 | height, 27 | radialSegments, 28 | heightSegments, 29 | openEnded, 30 | thetaStart, 31 | thetaLength 32 | } = this.attributes; 33 | const geometry = new _Cylinder(gl, { 34 | radiusTop, 35 | radiusBottom, 36 | height, 37 | radialSegments, 38 | heightSegments, 39 | openEnded, 40 | thetaStart, 41 | thetaLength 42 | }); 43 | this.setGeometry(geometry); 44 | } 45 | 46 | } 47 | 48 | _defineProperty(Cylinder, "Attr", CylinderAttr); 49 | 50 | registerNode(Cylinder, 'cylinder'); -------------------------------------------------------------------------------- /lib/node/plane.js: -------------------------------------------------------------------------------- 1 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2 | 3 | import { registerNode } from 'spritejs'; 4 | import { Plane as _Plane } from 'ogl'; 5 | import PlaneAttr from '../attribute/plane'; 6 | import Mesh3d from './mesh3d'; 7 | export default class Plane extends Mesh3d { 8 | /* override */ 9 | onPropertyChange(key, newValue, oldValue) { 10 | super.onPropertyChange(key, newValue, oldValue); 11 | 12 | if (key === 'width' || key === 'height' || key === 'widthSegments' || key === 'heightSegments') { 13 | if (newValue !== oldValue) { 14 | this.updateMesh(); 15 | } 16 | } 17 | } 18 | /* override */ 19 | 20 | 21 | remesh() { 22 | const gl = this.program.gl; 23 | const { 24 | width, 25 | height, 26 | widthSegments, 27 | heightSegments 28 | } = this.attributes; 29 | const geometry = new _Plane(gl, { 30 | width, 31 | height, 32 | widthSegments, 33 | heightSegments 34 | }); 35 | this.setGeometry(geometry); 36 | } 37 | 38 | } 39 | 40 | _defineProperty(Plane, "Attr", PlaneAttr); 41 | 42 | registerNode(Plane, 'plane'); -------------------------------------------------------------------------------- /lib/node/sphere.js: -------------------------------------------------------------------------------- 1 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2 | 3 | import { registerNode } from 'spritejs'; 4 | import { Sphere as _Sphere } from 'ogl'; 5 | import SphereAttr from '../attribute/sphere'; 6 | import Mesh3d from './mesh3d'; 7 | export default class Sphere extends Mesh3d { 8 | /* override */ 9 | onPropertyChange(key, newValue, oldValue) { 10 | super.onPropertyChange(key, newValue, oldValue); 11 | 12 | if (key === 'radius' || key === 'widthSegments' || key === 'heightSegments' || key === 'phiStart' || key === 'phiLength' || key === 'thetaStart' || key === 'thetaLength') { 13 | if (newValue !== oldValue) { 14 | this.updateMesh(); 15 | } 16 | } 17 | } 18 | /* override */ 19 | 20 | 21 | remesh() { 22 | const gl = this.program.gl; 23 | const { 24 | radius, 25 | widthSegments, 26 | heightSegments, 27 | phiStart, 28 | phiLength, 29 | thetaStart, 30 | thetaLength 31 | } = this.attributes; 32 | const geometry = new _Sphere(gl, { 33 | radius, 34 | widthSegments, 35 | heightSegments, 36 | phiStart, 37 | phiLength, 38 | thetaStart, 39 | thetaLength 40 | }); 41 | this.setGeometry(geometry); 42 | } 43 | 44 | } 45 | 46 | _defineProperty(Sphere, "Attr", SphereAttr); 47 | 48 | registerNode(Sphere, 'sphere'); -------------------------------------------------------------------------------- /lib/node/torus.js: -------------------------------------------------------------------------------- 1 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2 | 3 | import { registerNode } from 'spritejs'; 4 | import { Torus as _Torus } from 'ogl'; 5 | import TorusAttr from '../attribute/torus'; 6 | import Mesh3d from './mesh3d'; 7 | export default class Torus extends Mesh3d { 8 | /* override */ 9 | onPropertyChange(key, newValue, oldValue) { 10 | super.onPropertyChange(key, newValue, oldValue); 11 | 12 | if (key === 'radius' || key === 'tube' || key === 'radialSegments' || key === 'tubularSegments' || key === 'arc') { 13 | if (newValue !== oldValue) { 14 | this.updateMesh(); 15 | } 16 | } 17 | } 18 | /* override */ 19 | 20 | 21 | remesh() { 22 | const gl = this.program.gl; 23 | const { 24 | radius, 25 | tube, 26 | radialSegments, 27 | tubularSegments, 28 | arc 29 | } = this.attributes; 30 | const geometry = new _Torus(gl, { 31 | radius, 32 | tube, 33 | radialSegments, 34 | tubularSegments, 35 | arc 36 | }); 37 | this.setGeometry(geometry); 38 | } 39 | 40 | } 41 | 42 | _defineProperty(Torus, "Attr", TorusAttr); 43 | 44 | registerNode(Torus, 'torus'); -------------------------------------------------------------------------------- /lib/shader/base_geometry.frag: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | varying vec4 vColor; 6 | 7 | void main() { 8 | gl_FragColor = vColor; 9 | } 10 | `; -------------------------------------------------------------------------------- /lib/shader/base_geometry.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec4 color; 7 | 8 | uniform mat4 modelViewMatrix; 9 | uniform mat4 projectionMatrix; 10 | 11 | varying vec4 vColor; 12 | 13 | void main() { 14 | vColor = color; 15 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);; 16 | } 17 | `; -------------------------------------------------------------------------------- /lib/shader/dashline.frag: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | 4 | uniform float uTotalLength; 5 | uniform float uDashLength; 6 | uniform float uDashOffset; 7 | 8 | varying vec4 vColor; 9 | varying vec2 vUv; 10 | varying float fSeg; 11 | 12 | void main() { 13 | float f = fract((uDashOffset + fSeg) / (2.0 * uDashLength)); 14 | f = 1.0 - step(0.5, f); 15 | gl_FragColor = vColor * f; 16 | } 17 | `; -------------------------------------------------------------------------------- /lib/shader/dashline.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | attribute vec3 position; 4 | attribute vec3 next; 5 | attribute vec3 prev; 6 | attribute vec2 uv; 7 | attribute float side; 8 | attribute vec4 color; 9 | attribute float seg; 10 | 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 projectionMatrix; 13 | uniform vec2 uResolution; 14 | uniform float uDPR; 15 | uniform float uThickness; 16 | uniform float uMiter; 17 | 18 | varying vec2 vUv; 19 | varying vec4 vColor; 20 | varying float fSeg; 21 | 22 | vec4 getPosition() { 23 | mat4 mvp = projectionMatrix * modelViewMatrix; 24 | vec4 current = mvp * vec4(position, 1); 25 | vec4 nextPos = mvp * vec4(next, 1); 26 | vec4 prevPos = mvp * vec4(prev, 1); 27 | vec2 aspect = vec2(uResolution.x / uResolution.y, 1); 28 | vec2 currentScreen = current.xy / current.w * aspect; 29 | vec2 nextScreen = nextPos.xy / nextPos.w * aspect; 30 | vec2 prevScreen = prevPos.xy / prevPos.w * aspect; 31 | 32 | vec2 dir1 = normalize(currentScreen - prevScreen); 33 | vec2 dir2 = normalize(nextScreen - currentScreen); 34 | vec2 dir = normalize(dir1 + dir2); 35 | 36 | vec2 normal = vec2(-dir.y, dir.x); 37 | normal /= mix(1.0, max(0.3, dot(normal, vec2(-dir1.y, dir1.x))), uMiter); 38 | normal /= aspect; 39 | float pixelWidthRatio = 1.0 / (uResolution.y / uDPR); 40 | float pixelWidth = current.w * pixelWidthRatio; 41 | normal *= pixelWidth * uThickness; 42 | current.xy -= normal * side; 43 | return current; 44 | } 45 | 46 | void main() { 47 | vUv = uv; 48 | gl_Position = getPosition(); 49 | vColor = color; 50 | fSeg = seg; 51 | } 52 | `; -------------------------------------------------------------------------------- /lib/shader/geometry.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 viewMatrix; 11 | uniform mat4 projectionMatrix; 12 | uniform mat3 normalMatrix; 13 | uniform vec3 cameraPosition; 14 | 15 | varying vec3 vNormal; 16 | varying vec4 vColor; 17 | varying vec4 vPos; 18 | varying vec3 vCameraPos; 19 | 20 | void main() { 21 | vNormal = normalize(normalMatrix * normal); 22 | vPos = modelViewMatrix * vec4(position, 1.0);; 23 | vColor = color; 24 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 25 | gl_Position = projectionMatrix * vPos; 26 | } 27 | `; -------------------------------------------------------------------------------- /lib/shader/geometry_normal_map_100.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec2 uv; 7 | attribute vec3 normal; 8 | attribute vec4 color; 9 | 10 | uniform mat3 normalMatrix; 11 | uniform mat4 modelMatrix; 12 | uniform mat4 modelViewMatrix; 13 | uniform mat4 viewMatrix; 14 | uniform mat4 projectionMatrix; 15 | uniform vec3 cameraPosition; 16 | 17 | varying vec2 vUv; 18 | varying vec3 vNormal; 19 | varying vec4 vColor; 20 | varying vec4 vPos; 21 | varying vec3 vCameraPos; 22 | 23 | void main() { 24 | vUv = uv; 25 | vNormal = normalize(normalMatrix * normal); 26 | vColor = color; 27 | vPos = modelViewMatrix * vec4(position, 1.0); 28 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 29 | 30 | gl_Position = projectionMatrix * vPos; 31 | } 32 | `; -------------------------------------------------------------------------------- /lib/shader/geometry_normal_map_300.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | #version 300 es 3 | precision highp float; 4 | precision highp int; 5 | 6 | in vec3 position; 7 | in vec2 uv; 8 | in vec3 normal; 9 | in vec4 color; 10 | 11 | uniform mat3 normalMatrix; 12 | uniform mat4 modelMatrix; 13 | uniform mat4 modelViewMatrix; 14 | uniform mat4 viewMatrix; 15 | uniform mat4 projectionMatrix; 16 | uniform vec3 cameraPosition; 17 | 18 | out vec2 vUv; 19 | out vec3 vNormal; 20 | out vec4 vColor; 21 | out vec4 vPos; 22 | out vec3 vCameraPos; 23 | 24 | void main() { 25 | vUv = uv; 26 | vNormal = normalize(normalMatrix * normal); 27 | vColor = color; 28 | vPos = modelViewMatrix * vec4(position, 1.0); 29 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 30 | 31 | gl_Position = projectionMatrix * vPos; 32 | } 33 | `; -------------------------------------------------------------------------------- /lib/shader/geometry_with_shadow.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | 9 | uniform mat4 modelMatrix; 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | uniform mat3 normalMatrix; 14 | 15 | uniform mat4 shadowViewMatrix; 16 | uniform mat4 shadowProjectionMatrix; 17 | uniform vec3 cameraPosition; 18 | 19 | varying vec3 vNormal; 20 | varying vec4 vColor; 21 | varying vec4 vLightNDC; 22 | varying vec4 vPos; 23 | varying vec3 vCameraPos; 24 | 25 | // Matrix to shift range from -1->1 to 0->1 26 | const mat4 depthScaleMatrix = mat4( 27 | 0.5, 0, 0, 0, 28 | 0, 0.5, 0, 0, 29 | 0, 0, 0.5, 0, 30 | 0.5, 0.5, 0.5, 1 31 | ); 32 | 33 | void main() { 34 | vNormal = normalize(normalMatrix * normal); 35 | vPos = modelViewMatrix * vec4(position, 1.0); 36 | vColor = color; 37 | vLightNDC = depthScaleMatrix * shadowProjectionMatrix * shadowViewMatrix * modelMatrix * vec4(position, 1.0); 38 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 39 | gl_Position = projectionMatrix * vPos; 40 | } 41 | `; -------------------------------------------------------------------------------- /lib/shader/normal.frag: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | varying vec3 vNormal; 6 | 7 | void main() { 8 | gl_FragColor.rgb = normalize(vNormal); 9 | gl_FragColor.a = 1.0; 10 | } 11 | `; -------------------------------------------------------------------------------- /lib/shader/normal.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | 8 | uniform mat3 normalMatrix; 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 projectionMatrix; 11 | 12 | varying vec3 vNormal; 13 | 14 | void main() { 15 | vNormal = normalize(normalMatrix * normal); 16 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 17 | } 18 | `; -------------------------------------------------------------------------------- /lib/shader/polyline.frag: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | 4 | varying vec4 vColor; 5 | 6 | void main() { 7 | gl_FragColor = vColor; 8 | } 9 | `; -------------------------------------------------------------------------------- /lib/shader/polyline.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | attribute vec3 position; 4 | attribute vec3 next; 5 | attribute vec3 prev; 6 | attribute float side; 7 | attribute vec4 color; 8 | 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 projectionMatrix; 11 | uniform vec2 uResolution; 12 | uniform float uDPR; 13 | uniform float uThickness; 14 | uniform float uMiter; 15 | 16 | varying vec4 vColor; 17 | 18 | vec4 getPosition() { 19 | mat4 mvp = projectionMatrix * modelViewMatrix; 20 | vec4 current = mvp * vec4(position, 1); 21 | vec4 nextPos = mvp * vec4(next, 1); 22 | vec4 prevPos = mvp * vec4(prev, 1); 23 | vec2 aspect = vec2(uResolution.x / uResolution.y, 1); 24 | vec2 currentScreen = current.xy / current.w * aspect; 25 | vec2 nextScreen = nextPos.xy / nextPos.w * aspect; 26 | vec2 prevScreen = prevPos.xy / prevPos.w * aspect; 27 | 28 | vec2 dir1 = normalize(currentScreen - prevScreen); 29 | vec2 dir2 = normalize(nextScreen - currentScreen); 30 | vec2 dir = normalize(dir1 + dir2); 31 | 32 | vec2 normal = vec2(-dir.y, dir.x); 33 | normal /= mix(1.0, max(0.3, dot(normal, vec2(-dir1.y, dir1.x))), uMiter); 34 | normal /= aspect; 35 | float pixelWidthRatio = 1.0 / (uResolution.y / uDPR); 36 | float pixelWidth = current.w * pixelWidthRatio; 37 | normal *= pixelWidth * uThickness; 38 | current.xy -= normal * side; 39 | return current; 40 | } 41 | 42 | void main() { 43 | gl_Position = getPosition(); 44 | vColor = color; 45 | } 46 | `; -------------------------------------------------------------------------------- /lib/shader/texture.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | attribute vec2 uv; 9 | 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | uniform mat3 normalMatrix; 14 | uniform vec3 cameraPosition; 15 | 16 | varying vec3 vNormal; 17 | varying vec4 vColor; 18 | varying vec2 vUv; 19 | varying vec4 vPos; 20 | varying vec3 vCameraPos; 21 | 22 | void main() { 23 | vNormal = normalize(normalMatrix * normal); 24 | vPos = modelViewMatrix * vec4(position, 1.0); 25 | vColor = color; 26 | vUv = uv; 27 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 28 | gl_Position = projectionMatrix * vPos; 29 | } 30 | `; -------------------------------------------------------------------------------- /lib/shader/texture_cube.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 viewMatrix; 11 | uniform mat4 projectionMatrix; 12 | uniform mat3 normalMatrix; 13 | uniform vec3 cameraPosition; 14 | 15 | varying vec3 vNormal; 16 | varying vec3 vDir; 17 | varying vec4 vColor; 18 | varying vec4 vPos; 19 | varying vec3 vCameraPos; 20 | 21 | void main() { 22 | vNormal = normalize(normalMatrix * normal); 23 | vPos = modelViewMatrix * vec4(position, 1.0); 24 | vDir = normalize(position); 25 | vColor = color; 26 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 27 | gl_Position = projectionMatrix * vPos; 28 | } 29 | `; -------------------------------------------------------------------------------- /lib/shader/texture_normal_map_100.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec2 uv; 7 | attribute vec3 normal; 8 | attribute vec4 color; 9 | 10 | uniform mat3 normalMatrix; 11 | uniform mat4 modelMatrix; 12 | uniform mat4 modelViewMatrix; 13 | uniform mat4 viewMatrix; 14 | uniform mat4 projectionMatrix; 15 | uniform vec3 cameraPosition; 16 | 17 | varying vec2 vUv; 18 | varying vec3 vNormal; 19 | varying vec4 vColor; 20 | varying vec4 vPos; 21 | varying vec3 vCameraPos; 22 | 23 | void main() { 24 | vUv = uv; 25 | vNormal = normalize(normalMatrix * normal); 26 | vColor = color; 27 | vPos = modelViewMatrix * vec4(position, 1.0); 28 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 29 | 30 | gl_Position = projectionMatrix * vPos; 31 | } 32 | `; -------------------------------------------------------------------------------- /lib/shader/texture_normal_map_300.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | #version 300 es 3 | precision highp float; 4 | precision highp int; 5 | 6 | in vec3 position; 7 | in vec2 uv; 8 | in vec3 normal; 9 | in vec4 color; 10 | 11 | uniform mat3 normalMatrix; 12 | uniform mat4 modelMatrix; 13 | uniform mat4 modelViewMatrix; 14 | uniform mat4 viewMatrix; 15 | uniform mat4 projectionMatrix; 16 | uniform vec3 cameraPosition; 17 | 18 | out vec2 vUv; 19 | out vec3 vNormal; 20 | out vec4 vColor; 21 | out vec4 vPos; 22 | out vec3 vCameraPos; 23 | 24 | void main() { 25 | vUv = uv; 26 | vNormal = normalize(normalMatrix * normal); 27 | vColor = color; 28 | vPos = modelViewMatrix * vec4(position, 1.0); 29 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 30 | 31 | gl_Position = projectionMatrix * vPos; 32 | } 33 | `; -------------------------------------------------------------------------------- /lib/shader/texture_with_shadow.vert: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | attribute vec2 uv; 9 | 10 | uniform mat4 modelMatrix; 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 viewMatrix; 13 | uniform mat4 projectionMatrix; 14 | uniform mat3 normalMatrix; 15 | uniform vec3 cameraPosition; 16 | 17 | varying vec3 vNormal; 18 | varying vec2 vUv; 19 | varying vec4 vColor; 20 | varying vec4 vLightNDC; 21 | varying vec4 vPos; 22 | varying vec3 vCameraPos; 23 | 24 | uniform mat4 shadowViewMatrix; 25 | uniform mat4 shadowProjectionMatrix; 26 | 27 | // Matrix to shift range from -1->1 to 0->1 28 | const mat4 depthScaleMatrix = mat4( 29 | 0.5, 0, 0, 0, 30 | 0, 0.5, 0, 0, 31 | 0, 0, 0.5, 0, 32 | 0.5, 0.5, 0.5, 1 33 | ); 34 | 35 | void main() { 36 | vNormal = normalize(normalMatrix * normal); 37 | vPos = modelViewMatrix * vec4(position, 1.0); 38 | vColor = color; 39 | vUv = uv; 40 | vLightNDC = depthScaleMatrix * shadowProjectionMatrix * shadowViewMatrix * modelMatrix * vec4(position, 1.0); 41 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 42 | gl_Position = projectionMatrix * vPos; 43 | } 44 | `; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sprite-extend-3d", 3 | "version": "0.14.7", 4 | "description": "The 3d part of spritejs v3.", 5 | "main": "dist/sprite-extend-3d.js", 6 | "module": "lib/index.js", 7 | "typings": "typings/sprite-extend-3d.js", 8 | "scripts": { 9 | "start": "webpack-dev-server --env.server=examples --watch-poll", 10 | "compile": "rm -rf lib/* && babel src -d lib && node ./scripts/compile-shaders.js", 11 | "spritejs:update": "cp ./node_modules/spritejs/dist/spritejs.es.js ./examples/js/spritejs.js", 12 | "build": "webpack --env.mode=none & webpack --env.mode=production & webpack --env.mode=none --env.module && cp ./dist/sprite-extend-3d.esm.js ./examples/lib", 13 | "build:dev": "webpack --env.mode=none", 14 | "docs": "rm -rf ./docs && cp -R ./examples ./docs && cp -R ./dist/* ./docs/js/ && echo '3d.spritejs.org' > ./docs/CNAME", 15 | "prepublishOnly": "npm run compile && npm run build", 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "keywords": [], 19 | "author": "akira-cn", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@babel/cli": "^7.4.4", 23 | "@babel/core": "^7.4.5", 24 | "@babel/plugin-proposal-class-properties": "^7.4.4", 25 | "@babel/plugin-transform-runtime": "^7.4.4", 26 | "@babel/preset-env": "^7.4.5", 27 | "@purtuga/esm-webpack-plugin": "^1.2.1", 28 | "babel-eslint": "^10.0.1", 29 | "babel-loader": "^8.0.6", 30 | "eslint": "^5.16.0", 31 | "eslint-config-sprite": "^1.0.6", 32 | "eslint-plugin-html": "^5.0.5", 33 | "raw-loader": "^4.0.0", 34 | "webgl-obj-loader": "^2.0.6", 35 | "webpack": "^4.33.0", 36 | "webpack-cli": "^3.3.4", 37 | "webpack-dev-server": "^3.11.0" 38 | }, 39 | "dependencies": { 40 | "@babel/runtime": "^7.4.5", 41 | "ogl": "0.0.76", 42 | "spritejs": "^3.7.21" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scripts/compile-shaders.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | 5 | const sourceDir = path.resolve(__dirname, '../src/shader'); 6 | const destDir = path.resolve(__dirname, '../lib/shader'); 7 | 8 | fs.readdir(sourceDir, (err, files) => { 9 | files.forEach((file) => { 10 | if(/\.(vert|frag)/.test(file)) { 11 | const sourcePath = path.resolve(sourceDir, file); 12 | const content = fs.readFileSync(sourcePath, {encoding: 'utf-8'}); 13 | const destPath = path.resolve(destDir, file); 14 | fs.writeFileSync(destPath, `export default \` 15 | ${content} 16 | \`;`); 17 | } 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/attribute/camera.js: -------------------------------------------------------------------------------- 1 | import Node3dAttr from './node3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class GameraAttr extends Node3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | near: 0.1, 12 | far: 100, 13 | fov: 45, 14 | aspect: 1, 15 | left: undefined, 16 | right: undefined, 17 | bottom: undefined, 18 | top: undefined, 19 | zoom: 1, 20 | mode: 'perspective', // perspective - 透视相机, orthographic - 正交投影相机 21 | }); 22 | } 23 | 24 | get near() { 25 | return this[getAttribute]('near'); 26 | } 27 | 28 | set near(value) { 29 | this[setAttribute]('near', value); 30 | } 31 | 32 | get far() { 33 | return this[getAttribute]('far'); 34 | } 35 | 36 | set far(value) { 37 | this[setAttribute]('far', value); 38 | } 39 | 40 | get fov() { 41 | return this[getAttribute]('fov'); 42 | } 43 | 44 | set fov(value) { 45 | this[setAttribute]('fov', value); 46 | } 47 | 48 | get aspect() { 49 | return this[getAttribute]('aspect'); 50 | } 51 | 52 | set aspect(value) { 53 | this[setAttribute]('aspect', value); 54 | } 55 | 56 | get left() { 57 | return this[getAttribute]('left'); 58 | } 59 | 60 | set left(value) { 61 | this[setAttribute]('left', value); 62 | } 63 | 64 | get right() { 65 | return this[getAttribute]('right'); 66 | } 67 | 68 | set right(value) { 69 | this[setAttribute]('right', value); 70 | } 71 | 72 | get top() { 73 | return this[getAttribute]('top'); 74 | } 75 | 76 | set top(value) { 77 | this[setAttribute]('top', value); 78 | } 79 | 80 | get bottom() { 81 | return this[getAttribute]('bottom'); 82 | } 83 | 84 | set bottom(value) { 85 | this[setAttribute]('bottom', value); 86 | } 87 | 88 | get zoom() { 89 | return this[getAttribute]('zoom'); 90 | } 91 | 92 | set zoom(value) { 93 | this[setAttribute]('zoom', value); 94 | } 95 | 96 | get mode() { 97 | return this[getAttribute]('mode'); 98 | } 99 | 100 | set mode(value) { 101 | if(value && value !== 'perspective' && value !== 'orthographic') { 102 | throw new TypeError('Invalid camera mode.'); 103 | } 104 | this[setAttribute]('mode', value); 105 | } 106 | } -------------------------------------------------------------------------------- /src/attribute/cube.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class CubeAttr extends Mesh3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | width: 1, 12 | height: 1, 13 | depth: 1, 14 | /* size */ 15 | widthSegments: 1, 16 | heightSegments: 1, 17 | depthSegments: 1, 18 | /* override */ 19 | colorDivisor: 4, 20 | }); 21 | } 22 | 23 | get width() { 24 | return this[getAttribute]('width'); 25 | } 26 | 27 | set width(value) { 28 | this[setAttribute]('width', value); 29 | } 30 | 31 | get height() { 32 | return this[getAttribute]('height'); 33 | } 34 | 35 | set height(value) { 36 | this[setAttribute]('height', value); 37 | } 38 | 39 | get size() { 40 | return [this.width, this.height, this.depth]; 41 | } 42 | 43 | set size(value) { 44 | if(!Array.isArray(value)) value = [value, value, value]; 45 | this.width = value[0]; 46 | this.height = value[1]; 47 | this.depth = value[2]; 48 | } 49 | 50 | get depth() { 51 | return this[getAttribute]('depth'); 52 | } 53 | 54 | set depth(value) { 55 | this[setAttribute]('depth', value); 56 | } 57 | 58 | get widthSegments() { 59 | return this[getAttribute]('widthSegments'); 60 | } 61 | 62 | set widthSegments(value) { 63 | this[setAttribute]('widthSegments', value); 64 | } 65 | 66 | get heightSegments() { 67 | return this[getAttribute]('heightSegments'); 68 | } 69 | 70 | set heightSegments(value) { 71 | this[setAttribute]('heightSegments', value); 72 | } 73 | 74 | get depthSegments() { 75 | return this[getAttribute]('depthSegments'); 76 | } 77 | 78 | set depthSegments(value) { 79 | this[setAttribute]('depthSegments', value); 80 | } 81 | } -------------------------------------------------------------------------------- /src/attribute/cylinder.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class CylinderAttr extends Mesh3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | radiusTop: 0.5, 12 | radiusBottom: 0.5, 13 | /* radius */ 14 | height: 1, 15 | radialSegments: 16, 16 | heightSegments: 1, 17 | openEnded: false, 18 | thetaStart: 0, 19 | thetaLength: Math.PI * 2, 20 | }); 21 | } 22 | 23 | get radiusTop() { 24 | return this[getAttribute]('radiusTop'); 25 | } 26 | 27 | set radiusTop(value) { 28 | this[setAttribute]('radiusTop', value); 29 | } 30 | 31 | get radiusBottom() { 32 | return this[getAttribute]('radiusBottom'); 33 | } 34 | 35 | set radiusBottom(value) { 36 | this[setAttribute]('radiusBottom', value); 37 | } 38 | 39 | get radius() { 40 | return [this.radiusTop, this.radiusBottom]; 41 | } 42 | 43 | set radius(value) { 44 | if(!Array.isArray(value)) value = [value, value]; 45 | this.radiusTop = value[0]; 46 | this.radiusBottom = value[1]; 47 | } 48 | 49 | get height() { 50 | return this[getAttribute]('height'); 51 | } 52 | 53 | set height(value) { 54 | this[setAttribute]('height', value); 55 | } 56 | 57 | get radialSegments() { 58 | return this[getAttribute]('radialSegments'); 59 | } 60 | 61 | set radialSegments(value) { 62 | this[setAttribute]('radialSegments', value); 63 | } 64 | 65 | get heightSegments() { 66 | return this[getAttribute]('heightSegments'); 67 | } 68 | 69 | set heightSegments(value) { 70 | this[setAttribute]('heightSegments', value); 71 | } 72 | 73 | get openEnded() { 74 | return this[getAttribute]('openEnded'); 75 | } 76 | 77 | set openEnded(value) { 78 | this[setAttribute]('openEnded', value); 79 | } 80 | 81 | get thetaStart() { 82 | return this[getAttribute]('thetaStart'); 83 | } 84 | 85 | set thetaStart(value) { 86 | this[setAttribute]('thetaStart', value); 87 | } 88 | 89 | get thetaLength() { 90 | return this[getAttribute]('thetaLength'); 91 | } 92 | 93 | set thetaLength(value) { 94 | this[setAttribute]('thetaLength', value); 95 | } 96 | } -------------------------------------------------------------------------------- /src/attribute/mesh3d.js: -------------------------------------------------------------------------------- 1 | import {Color} from 'spritejs'; 2 | import Node3dAttr from './node3d'; 3 | 4 | const setAttribute = Symbol.for('spritejs_setAttribute'); 5 | const getAttribute = Symbol.for('spritejs_getAttribute'); 6 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 7 | 8 | export default class Mesh3dAttr extends Node3dAttr { 9 | constructor(subject) { 10 | super(subject); 11 | this[setDefault]({ 12 | mode: 'TRIANGLES', // POINTS, LINES, LINE_LOOP, LINE_STRIP, TRIANGLES 13 | colors: [0.5, 0.5, 0.5, 1], 14 | colorDivisor: 3, 15 | raycast: 'box', // box sphere none 16 | }); 17 | } 18 | 19 | get colors() { 20 | return this[getAttribute]('colors'); 21 | } 22 | 23 | set colors(value) { 24 | if(typeof value === 'string') { 25 | value = value.replace(/\s*,\s*/g, ','); 26 | let colors = value.split(/\s+/g); 27 | colors = colors.map((c) => { 28 | return new Color(c); 29 | }); 30 | value = colors.reduce((a, b) => [...a, ...b]); 31 | } else if(Array.isArray(value)) { 32 | if(typeof value[0] === 'string') { 33 | value = value.reduce((a, b) => { 34 | a.push(...(new Color(b))); 35 | return a; 36 | }, []); 37 | } else if(Array.isArray(value[0])) { 38 | value = value.reduce((a, b) => [...a, ...b]); 39 | } 40 | } 41 | this[setAttribute]('colors', value); 42 | } 43 | 44 | get colorDivisor() { 45 | return this[getAttribute]('colorDivisor'); 46 | } 47 | 48 | set colorDivisor(value) { 49 | this[setAttribute]('colorDivisor', value); 50 | } 51 | 52 | get mode() { 53 | return this[getAttribute]('mode'); 54 | } 55 | 56 | set mode(value) { 57 | if(typeof value === 'number' && value >= 0 && value < 7) { 58 | value = ['POINTS', 'LINES', 'LINE_LOOP', 'LINE_STRIP', 'TRIANGLES', 'TRIANGLE_STRIP', 'TRIANGLE_FAN'][value]; 59 | } 60 | if(value && value !== 'TRIANGLES' && value !== 'POINTS' && value !== 'LINES' && value !== 'LINE_LOOP' && value !== 'LINE_STRIP' 61 | && value !== 'TRIANGLE_STRIP' && value !== 'TRIANGLE_FAN') { 62 | throw new TypeError('Invalid mode value.'); 63 | } 64 | this[setAttribute]('mode', value); 65 | } 66 | 67 | get raycast() { 68 | return this[getAttribute]('raycast'); 69 | } 70 | 71 | set raycast(value) { 72 | this[setAttribute]('raycast', value); 73 | } 74 | } -------------------------------------------------------------------------------- /src/attribute/plane.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class PlaneAttr extends Mesh3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | width: 1, 12 | height: 1, 13 | widthSegments: 1, 14 | heightSegments: 1, 15 | }); 16 | } 17 | 18 | get width() { 19 | return this[getAttribute]('width'); 20 | } 21 | 22 | set width(value) { 23 | this[setAttribute]('width', value); 24 | } 25 | 26 | get height() { 27 | return this[getAttribute]('height'); 28 | } 29 | 30 | set height(value) { 31 | this[setAttribute]('height', value); 32 | } 33 | 34 | get widthSegments() { 35 | return this[getAttribute]('widthSegments'); 36 | } 37 | 38 | set widthSegments(value) { 39 | this[setAttribute]('widthSegments', value); 40 | } 41 | 42 | get heightSegments() { 43 | return this[getAttribute]('heightSegments'); 44 | } 45 | 46 | set heightSegments(value) { 47 | this[setAttribute]('heightSegments', value); 48 | } 49 | } -------------------------------------------------------------------------------- /src/attribute/polyline3d.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class PolylineAttr extends Mesh3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | points: [], 12 | raycast: 'none', 13 | }); 14 | } 15 | 16 | get points() { 17 | return this[getAttribute]('points'); 18 | } 19 | 20 | set points(value) { 21 | if(Array.isArray(value)) { 22 | value = value.reduce((a, b) => { 23 | if(Array.isArray(b)) { 24 | return [...a, ...b]; 25 | } 26 | return [...a, b]; 27 | }, []); 28 | } 29 | // if(value) { // 要去掉重复的点 30 | // if(value.length % 3) throw new Error('Invalid points set'); 31 | // const points = [value[0], value[1], value[2]]; 32 | // for(let i = 3; i < value.length; i += 3) { 33 | // if(value[i] !== value[i - 3] || value[i + 1] !== value[i - 2] || value[i + 2] !== value[i - 1]) { 34 | // points.push(value[i], value[i + 1], value[i + 2]); 35 | // } 36 | // } 37 | // value = points; 38 | // } 39 | this[setAttribute]('points', value); 40 | } 41 | } -------------------------------------------------------------------------------- /src/attribute/sphere.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class SphereAttr extends Mesh3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | radius: 0.5, 12 | widthSegments: 32, 13 | heightSegments: 16, 14 | phiStart: 0, 15 | phiLength: Math.PI * 2, 16 | thetaStart: 0, 17 | thetaLength: Math.PI, 18 | raycast: 'sphere', 19 | }); 20 | } 21 | 22 | get radius() { 23 | return this[getAttribute]('radius'); 24 | } 25 | 26 | set radius(value) { 27 | this[setAttribute]('radius', value); 28 | } 29 | 30 | get widthSegments() { 31 | return this[getAttribute]('widthSegments'); 32 | } 33 | 34 | set widthSegments(value) { 35 | this[setAttribute]('widthSegments', value); 36 | } 37 | 38 | get heightSegments() { 39 | return this[getAttribute]('heightSegments'); 40 | } 41 | 42 | set heightSegments(value) { 43 | this[setAttribute]('heightSegments', value); 44 | } 45 | 46 | get phiStart() { 47 | return this[getAttribute]('phiStart'); 48 | } 49 | 50 | set phiStart(value) { 51 | this[setAttribute]('phiStart', value); 52 | } 53 | 54 | get phiLength() { 55 | return this[getAttribute]('phiLength'); 56 | } 57 | 58 | set phiLength(value) { 59 | this[setAttribute]('phiLength', value); 60 | } 61 | 62 | get thetaStart() { 63 | return this[getAttribute]('thetaStart'); 64 | } 65 | 66 | set thetaStart(value) { 67 | this[setAttribute]('thetaStart', value); 68 | } 69 | 70 | get thetaLength() { 71 | return this[getAttribute]('thetaLength'); 72 | } 73 | 74 | set thetaLength(value) { 75 | this[setAttribute]('thetaLength', value); 76 | } 77 | } -------------------------------------------------------------------------------- /src/attribute/torus.js: -------------------------------------------------------------------------------- 1 | import Mesh3dAttr from './mesh3d'; 2 | 3 | const setAttribute = Symbol.for('spritejs_setAttribute'); 4 | const getAttribute = Symbol.for('spritejs_getAttribute'); 5 | const setDefault = Symbol.for('spritejs_setAttributeDefault'); 6 | 7 | export default class TorusAttr extends Mesh3dAttr { 8 | constructor(subject) { 9 | super(subject); 10 | this[setDefault]({ 11 | radius: 0.5, 12 | tube: 0.2, 13 | radialSegments: 8, 14 | tubularSegments: 6, 15 | arc: Math.PI * 2, 16 | }); 17 | } 18 | 19 | get radius() { 20 | return this[getAttribute]('radius'); 21 | } 22 | 23 | set radius(value) { 24 | this[setAttribute]('radius', value); 25 | } 26 | 27 | get tube() { 28 | return this[getAttribute]('tube'); 29 | } 30 | 31 | set tube(value) { 32 | this[setAttribute]('tube', value); 33 | } 34 | 35 | get radialSegments() { 36 | return this[getAttribute]('radialSegments'); 37 | } 38 | 39 | set radialSegments(value) { 40 | this[setAttribute]('radialSegments', value); 41 | } 42 | 43 | get tubularSegments() { 44 | return this[getAttribute]('tubularSegments'); 45 | } 46 | 47 | set tubularSegments(value) { 48 | this[setAttribute]('tubularSegments', value); 49 | } 50 | 51 | get arc() { 52 | return this[getAttribute]('arc'); 53 | } 54 | 55 | set arc(value) { 56 | this[setAttribute]('arc', value); 57 | } 58 | } -------------------------------------------------------------------------------- /src/helper/color-attribute.js: -------------------------------------------------------------------------------- 1 | export function colorAttribute(node, geometry) { 2 | const updateColor = geometry.attributes.color; 3 | 4 | const positions = geometry.attributes.position.data; 5 | const size = geometry.attributes.position.size || 3; 6 | const len = positions.length / size; 7 | 8 | const color = updateColor ? updateColor.data : new Float32Array(4 * len); 9 | const colors = node.attributes.colors; 10 | const colorLen = colors.length / 4; 11 | const colorDivisor = node.attributes.colorDivisor; 12 | 13 | for(let i = 0; i < len; i++) { 14 | // const color = colors 15 | const idx = Math.floor(i / colorDivisor) % colorLen; 16 | color[4 * i] = colors[idx * 4]; 17 | color[4 * i + 1] = colors[idx * 4 + 1]; 18 | color[4 * i + 2] = colors[idx * 4 + 2]; 19 | color[4 * i + 3] = colors[idx * 4 + 3]; 20 | } 21 | 22 | if(updateColor) updateColor.needsUpdate = true; 23 | 24 | return {size: 4, data: color}; 25 | } -------------------------------------------------------------------------------- /src/helper/curve.js: -------------------------------------------------------------------------------- 1 | import {Curve as _Curve, Vec3} from 'ogl'; 2 | 3 | export default class Curve extends _Curve { 4 | constructor({points, divisions, type} = {}) { 5 | if(Array.isArray(points) && points[0] && !(points[0] instanceof Vec3)) { 6 | points = points.map(p => new Vec3().copy(p)); 7 | } 8 | super({points, divisions, type}); 9 | } 10 | } -------------------------------------------------------------------------------- /src/helper/light.js: -------------------------------------------------------------------------------- 1 | import {parseColor} from './parse-color'; 2 | 3 | export default class Light { 4 | static DIRECTIONAL_LIGHT = 0; 5 | 6 | static POINT_LIGHT = 1; 7 | 8 | static SPOT_LIGHT = 2; 9 | 10 | constructor({angle, direction, position, blur = 0, color = [1, 1, 1, 1], decay = [0, 0, 1]} = {}) { 11 | this.angle = angle; 12 | this.blur = blur; 13 | this.color = color ? parseColor(color) : undefined; 14 | this.decay = decay; 15 | this.direction = direction; 16 | this.position = position; 17 | if(this.position && this.direction && this.angle == null) { 18 | this.angle = Math.PI / 3; 19 | } 20 | } 21 | 22 | get type() { 23 | if(this.position && this.direction) return Light.SPOT_LIGHT; 24 | if(this.position) return Light.POINT_LIGHT; 25 | if(this.direction) return Light.DIRECTIONAL_LIGHT; 26 | throw new Error('unknown light'); 27 | } 28 | } -------------------------------------------------------------------------------- /src/helper/parse-color.js: -------------------------------------------------------------------------------- 1 | import {Color} from 'spritejs'; 2 | 3 | export function parseColor(colors) { 4 | if(Array.isArray(colors)) { 5 | return colors.map((c) => { 6 | if(typeof c === 'string') { 7 | return new Color(c); 8 | } 9 | return c; 10 | }); 11 | } 12 | return typeof colors === 'string' ? new Color(colors) : colors; 13 | } -------------------------------------------------------------------------------- /src/helper/shadow.js: -------------------------------------------------------------------------------- 1 | import {Shadow as _Shadow} from 'ogl'; 2 | 3 | // https://github.com/oframe/ogl/blob/master/src/extras/Shadow.js 4 | export default class Shadow extends _Shadow { 5 | async add(node, opts = {}) { 6 | await node.model; 7 | opts.mesh = node.body; 8 | node.addEventListener('updatemesh', (evt) => { 9 | const oldMesh = evt.detail.oldMesh; 10 | this.castMeshes = this.castMeshes.filter(mesh => mesh !== oldMesh); 11 | this.add(node, opts); 12 | }); 13 | super.add(opts); 14 | } 15 | 16 | remove(node) { 17 | const mesh = node.body; 18 | if(mesh) { 19 | const idx = this.castMeshes.indexOf(mesh); 20 | if(idx >= 0) { 21 | this.castMeshes.splice(idx, 1); 22 | return true; 23 | } 24 | } 25 | return false; 26 | } 27 | } -------------------------------------------------------------------------------- /src/helper/texture-loader.js: -------------------------------------------------------------------------------- 1 | import {TextureLoader as _TextureLoader} from 'ogl'; 2 | 3 | export default class TextureLoader { 4 | static load(layer, opts) { 5 | const texture = _TextureLoader.load(layer.gl, opts); 6 | if(texture && texture.loaded && texture.loaded.then) { 7 | // load loadKTX 8 | texture.loaded.then(() => { 9 | layer.forceUpdate(); 10 | }); 11 | } else if(texture && texture.then) { 12 | // load Image 13 | texture.then(() => { 14 | layer.forceUpdate(); 15 | }); 16 | } 17 | return texture; 18 | } 19 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import {Raycast, GPGPU, Vec2, Vec3, Vec4, Mat3, Mat4, Quat, Euler, RenderTarget as FrameBuffer} from 'ogl'; 2 | import Layer3d from './node/layer3d'; 3 | import Mesh3d from './node/mesh3d'; 4 | import Skin from './node/skin'; 5 | import Sphere from './node/sphere'; 6 | import Torus from './node/torus'; 7 | import Camera from './node/camera'; 8 | import Cube from './node/cube'; 9 | import Curve from './helper/curve'; 10 | import Plane from './node/plane'; 11 | import Polyline3d from './node/polyline3d'; 12 | import Cylinder from './node/cylinder'; 13 | import Path3d from './node/path3d'; 14 | import Group3d from './node/group3d'; 15 | import RenderTarget from './node/render-target'; 16 | import Shadow from './helper/shadow'; 17 | import TextureLoader from './helper/texture-loader'; 18 | import Geometry from './helper/geometry'; 19 | import Light from './helper/light'; 20 | import * as shaders from './shader'; 21 | 22 | export { 23 | Layer3d, 24 | Sphere, 25 | Torus, 26 | Plane, 27 | Polyline3d, 28 | Camera, 29 | Cube, 30 | Cylinder, 31 | Path3d, 32 | Mesh3d, 33 | Skin, 34 | Group3d, 35 | RenderTarget, 36 | Shadow, 37 | Light, 38 | TextureLoader, 39 | Geometry, 40 | Curve, 41 | shaders, 42 | Vec2, 43 | Vec3, 44 | Vec4, 45 | Mat3, 46 | Mat4, 47 | Quat, 48 | Euler, 49 | GPGPU, 50 | Raycast, 51 | FrameBuffer, 52 | }; -------------------------------------------------------------------------------- /src/node/cube.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {Box} from 'ogl'; 3 | import Mesh3d from './mesh3d'; 4 | import CubeAttr from '../attribute/cube'; 5 | 6 | export default class Cube extends Mesh3d { 7 | static Attr = CubeAttr; 8 | 9 | /* override */ 10 | onPropertyChange(key, newValue, oldValue) { 11 | super.onPropertyChange(key, newValue, oldValue); 12 | if(key === 'width' 13 | || key === 'height' 14 | || key === 'depth' 15 | || key === 'widthSegments' 16 | || key === 'heightSegments' 17 | || key === 'depthSegments') { 18 | if(newValue !== oldValue) { 19 | this.updateMesh(); 20 | } 21 | } 22 | } 23 | 24 | /* override */ 25 | remesh() { 26 | const gl = this.program.gl; 27 | const {width, height, depth, widthSegments, heightSegments, depthSegments} = this.attributes; 28 | const geometry = new Box(gl, { 29 | width, 30 | height, 31 | depth, 32 | widthSegments, 33 | heightSegments, 34 | depthSegments}); 35 | this.setGeometry(geometry); 36 | } 37 | } 38 | 39 | registerNode(Cube, 'cube'); -------------------------------------------------------------------------------- /src/node/cylinder.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {Cylinder as _Cylinder} from 'ogl'; 3 | import CylinderAttr from '../attribute/cylinder'; 4 | import Mesh3d from './mesh3d'; 5 | 6 | export default class Cylinder extends Mesh3d { 7 | static Attr = CylinderAttr; 8 | 9 | /* override */ 10 | onPropertyChange(key, newValue, oldValue) { 11 | super.onPropertyChange(key, newValue, oldValue); 12 | if(key === 'radiusTop' 13 | || key === 'radiusBottom' 14 | || key === 'height' 15 | || key === 'radialSegments' 16 | || key === 'heightSegments' 17 | || key === 'openEnded' 18 | || key === 'thetaStart' 19 | || key === 'thetaLength') { 20 | if(newValue !== oldValue) { 21 | this.updateMesh(); 22 | } 23 | } 24 | } 25 | 26 | /* override */ 27 | remesh() { 28 | const gl = this.program.gl; 29 | const {radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength} = this.attributes; 30 | 31 | const geometry = new _Cylinder(gl, { 32 | radiusTop, 33 | radiusBottom, 34 | height, 35 | radialSegments, 36 | heightSegments, 37 | openEnded, 38 | thetaStart, 39 | thetaLength}); 40 | this.setGeometry(geometry); 41 | } 42 | } 43 | 44 | registerNode(Cylinder, 'cylinder'); -------------------------------------------------------------------------------- /src/node/plane.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {Plane as _Plane} from 'ogl'; 3 | import PlaneAttr from '../attribute/plane'; 4 | import Mesh3d from './mesh3d'; 5 | 6 | export default class Plane extends Mesh3d { 7 | static Attr = PlaneAttr; 8 | 9 | /* override */ 10 | onPropertyChange(key, newValue, oldValue) { 11 | super.onPropertyChange(key, newValue, oldValue); 12 | if(key === 'width' 13 | || key === 'height' 14 | || key === 'widthSegments' 15 | || key === 'heightSegments') { 16 | if(newValue !== oldValue) { 17 | this.updateMesh(); 18 | } 19 | } 20 | } 21 | 22 | /* override */ 23 | remesh() { 24 | const gl = this.program.gl; 25 | const {width, height, widthSegments, heightSegments} = this.attributes; 26 | 27 | const geometry = new _Plane(gl, { 28 | width, 29 | height, 30 | widthSegments, 31 | heightSegments}); 32 | this.setGeometry(geometry); 33 | } 34 | } 35 | 36 | registerNode(Plane, 'plane'); -------------------------------------------------------------------------------- /src/node/render-target.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {RenderTarget as _RenderTarget} from 'ogl'; 3 | import Group3d from './group3d'; 4 | import Camera from './camera'; 5 | 6 | const _target = Symbol('target'); 7 | const _buffer = Symbol('buffer'); 8 | 9 | export default class RenderTarget extends Group3d { 10 | constructor(gl, { 11 | width = gl.canvas.width, 12 | height = gl.canvas.height, 13 | target = gl.FRAMEBUFFER, 14 | color = 1, // number of color attachments 15 | depth = true, 16 | stencil = false, 17 | depthTexture = false, // note - stencil breaks 18 | wrapS = gl.CLAMP_TO_EDGE, 19 | wrapT = gl.CLAMP_TO_EDGE, 20 | minFilter = gl.LINEAR, 21 | magFilter = minFilter, 22 | type = gl.UNSIGNED_BYTE, 23 | format = gl.RGBA, 24 | internalFormat = format, 25 | unpackAlignment, 26 | premultiplyAlpha, 27 | camera: cameraOptions, 28 | buffer = false, 29 | ...attrs} = {}) { 30 | super(attrs); 31 | 32 | const options = {width, 33 | height, 34 | target, 35 | color, 36 | depth, 37 | stencil, 38 | depthTexture, 39 | wrapS, 40 | wrapT, 41 | minFilter, 42 | magFilter, 43 | type, 44 | format, 45 | internalFormat, 46 | unpackAlignment, 47 | premultiplyAlpha}; 48 | 49 | this.options = options; 50 | this[_target] = new _RenderTarget(gl, options); 51 | 52 | if(buffer) { 53 | this[_buffer] = new _RenderTarget(gl, this.options); 54 | } 55 | 56 | if(cameraOptions) { 57 | const camera = new Camera(gl, cameraOptions); 58 | camera.connect(this, 0); 59 | this.camera = camera; 60 | } 61 | } 62 | 63 | get texture() { 64 | return this[_buffer] ? this[_buffer].texture : this[_target].texture; 65 | } 66 | 67 | renderBy(layer, {root = this, ...options} = {}) { 68 | const camera = this.camera ? this.camera.body : null; 69 | const target = this[_target]; 70 | 71 | this.dispatchEvent({type: 'beforerender', detail: {scene: root, camera, renderer: layer}}); 72 | 73 | layer.renderer.render({scene: root.body, camera, target, ...options}); 74 | this.dispatchEvent({type: 'afterrender', detail: {scene: root, camera, renderer: layer}}); 75 | return this[_target].texture; 76 | } 77 | 78 | swap() { 79 | if(this[_buffer] == null) { 80 | throw new Error('No buffer to swap. You must set buffer option to true when creating the renderTarget object.'); 81 | } 82 | [this[_target], this[_buffer]] = [this[_buffer], this[_target]]; 83 | } 84 | } 85 | 86 | registerNode(RenderTarget, 'rendertarget'); -------------------------------------------------------------------------------- /src/node/skin.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {Skin as _Skin} from 'ogl'; 3 | import Mesh3d from './mesh3d'; 4 | 5 | const _rig = Symbol('rig'); 6 | const _animations = []; 7 | 8 | function initAnimation(body, animationFrames) { 9 | const animation = body.addAnimation(animationFrames.data); 10 | const node = body._node; 11 | const elapsed = animationFrames.elapsed || 0; 12 | if(elapsed) { 13 | animation.elapsed = elapsed; 14 | body.update(); 15 | node.forceUpdate(); 16 | } 17 | Object.defineProperties(animationFrames, { 18 | animation: { 19 | get() { 20 | return animation; 21 | }, 22 | enumerable: true, 23 | }, 24 | elapsed: { 25 | get() { 26 | return animation.elapsed; 27 | }, 28 | set(value) { 29 | animation.elapsed = value; 30 | body.update(); 31 | node.forceUpdate(); 32 | }, 33 | enumerable: true, 34 | }, 35 | }); 36 | return animationFrames; 37 | } 38 | 39 | export default class Skin extends Mesh3d { 40 | constructor(program, {model, ...attrs} = {}) { 41 | super(program, {model, ...attrs}); 42 | this[_animations] = []; 43 | } 44 | 45 | get bones() { 46 | if(this[_rig]) { 47 | return this[_rig].bones; 48 | } 49 | return null; 50 | } 51 | 52 | /* override */ 53 | _createMesh({geometry, program}) { 54 | const rig = this[_rig]; 55 | return new _Skin(program.gl, {rig, geometry, program}); 56 | } 57 | 58 | addAnimation(animationData) { 59 | const animationFrames = {data: animationData}; 60 | 61 | const body = this.body; 62 | if(body.addAnimation) { 63 | initAnimation(body, animationFrames); 64 | } 65 | 66 | this[_animations].push(animationFrames); 67 | return animationFrames; 68 | } 69 | 70 | /* override */ 71 | setGeometry(model = this.model) { 72 | const rig = model.rig; 73 | this[_rig] = rig; 74 | delete model.rig; 75 | super.setGeometry(model); 76 | model.rig = rig; 77 | if(model !== this.geometry) { 78 | this.geometry.rig = rig; 79 | } 80 | this[_animations].forEach((frames) => { 81 | if(!frames.animation) { 82 | initAnimation(this.body, frames); 83 | } 84 | }); 85 | } 86 | } 87 | 88 | registerNode(Skin, 'skin'); -------------------------------------------------------------------------------- /src/node/sphere.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {Sphere as _Sphere} from 'ogl'; 3 | import SphereAttr from '../attribute/sphere'; 4 | import Mesh3d from './mesh3d'; 5 | 6 | export default class Sphere extends Mesh3d { 7 | static Attr = SphereAttr; 8 | 9 | /* override */ 10 | onPropertyChange(key, newValue, oldValue) { 11 | super.onPropertyChange(key, newValue, oldValue); 12 | if(key === 'radius' 13 | || key === 'widthSegments' 14 | || key === 'heightSegments' 15 | || key === 'phiStart' 16 | || key === 'phiLength' 17 | || key === 'thetaStart' 18 | || key === 'thetaLength') { 19 | if(newValue !== oldValue) { 20 | this.updateMesh(); 21 | } 22 | } 23 | } 24 | 25 | /* override */ 26 | remesh() { 27 | const gl = this.program.gl; 28 | const {radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength} = this.attributes; 29 | 30 | const geometry = new _Sphere(gl, { 31 | radius, 32 | widthSegments, 33 | heightSegments, 34 | phiStart, 35 | phiLength, 36 | thetaStart, 37 | thetaLength}); 38 | 39 | this.setGeometry(geometry); 40 | } 41 | } 42 | 43 | registerNode(Sphere, 'sphere'); -------------------------------------------------------------------------------- /src/node/torus.js: -------------------------------------------------------------------------------- 1 | import {registerNode} from 'spritejs'; 2 | import {Torus as _Torus} from 'ogl'; 3 | import TorusAttr from '../attribute/torus'; 4 | import Mesh3d from './mesh3d'; 5 | 6 | export default class Torus extends Mesh3d { 7 | static Attr = TorusAttr; 8 | 9 | /* override */ 10 | onPropertyChange(key, newValue, oldValue) { 11 | super.onPropertyChange(key, newValue, oldValue); 12 | if(key === 'radius' 13 | || key === 'tube' 14 | || key === 'radialSegments' 15 | || key === 'tubularSegments' 16 | || key === 'arc') { 17 | if(newValue !== oldValue) { 18 | this.updateMesh(); 19 | } 20 | } 21 | } 22 | 23 | /* override */ 24 | remesh() { 25 | const gl = this.program.gl; 26 | const {radius, tube, radialSegments, tubularSegments, arc} = this.attributes; 27 | 28 | const geometry = new _Torus(gl, { 29 | radius, 30 | tube, 31 | radialSegments, 32 | tubularSegments, 33 | arc}); 34 | 35 | this.setGeometry(geometry); 36 | } 37 | } 38 | 39 | registerNode(Torus, 'torus'); -------------------------------------------------------------------------------- /src/shader/base_geometry.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | varying vec4 vColor; 5 | 6 | void main() { 7 | gl_FragColor = vColor; 8 | } -------------------------------------------------------------------------------- /src/shader/base_geometry.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec4 color; 6 | 7 | uniform mat4 modelViewMatrix; 8 | uniform mat4 projectionMatrix; 9 | 10 | varying vec4 vColor; 11 | 12 | void main() { 13 | vColor = color; 14 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);; 15 | } -------------------------------------------------------------------------------- /src/shader/dashline.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform float uTotalLength; 4 | uniform float uDashLength; 5 | uniform float uDashOffset; 6 | 7 | varying vec4 vColor; 8 | varying vec2 vUv; 9 | varying float fSeg; 10 | 11 | void main() { 12 | float f = fract((uDashOffset + fSeg) / (2.0 * uDashLength)); 13 | f = 1.0 - step(0.5, f); 14 | gl_FragColor = vColor * f; 15 | } -------------------------------------------------------------------------------- /src/shader/dashline.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | attribute vec3 position; 3 | attribute vec3 next; 4 | attribute vec3 prev; 5 | attribute vec2 uv; 6 | attribute float side; 7 | attribute vec4 color; 8 | attribute float seg; 9 | 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 projectionMatrix; 12 | uniform vec2 uResolution; 13 | uniform float uDPR; 14 | uniform float uThickness; 15 | uniform float uMiter; 16 | 17 | varying vec2 vUv; 18 | varying vec4 vColor; 19 | varying float fSeg; 20 | 21 | vec4 getPosition() { 22 | mat4 mvp = projectionMatrix * modelViewMatrix; 23 | vec4 current = mvp * vec4(position, 1); 24 | vec4 nextPos = mvp * vec4(next, 1); 25 | vec4 prevPos = mvp * vec4(prev, 1); 26 | vec2 aspect = vec2(uResolution.x / uResolution.y, 1); 27 | vec2 currentScreen = current.xy / current.w * aspect; 28 | vec2 nextScreen = nextPos.xy / nextPos.w * aspect; 29 | vec2 prevScreen = prevPos.xy / prevPos.w * aspect; 30 | 31 | vec2 dir1 = normalize(currentScreen - prevScreen); 32 | vec2 dir2 = normalize(nextScreen - currentScreen); 33 | vec2 dir = normalize(dir1 + dir2); 34 | 35 | vec2 normal = vec2(-dir.y, dir.x); 36 | normal /= mix(1.0, max(0.3, dot(normal, vec2(-dir1.y, dir1.x))), uMiter); 37 | normal /= aspect; 38 | float pixelWidthRatio = 1.0 / (uResolution.y / uDPR); 39 | float pixelWidth = current.w * pixelWidthRatio; 40 | normal *= pixelWidth * uThickness; 41 | current.xy -= normal * side; 42 | return current; 43 | } 44 | 45 | void main() { 46 | vUv = uv; 47 | gl_Position = getPosition(); 48 | vColor = color; 49 | fSeg = seg; 50 | } -------------------------------------------------------------------------------- /src/shader/geometry.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec3 normal; 6 | attribute vec4 color; 7 | 8 | uniform mat4 modelViewMatrix; 9 | uniform mat4 viewMatrix; 10 | uniform mat4 projectionMatrix; 11 | uniform mat3 normalMatrix; 12 | uniform vec3 cameraPosition; 13 | 14 | varying vec3 vNormal; 15 | varying vec4 vColor; 16 | varying vec4 vPos; 17 | varying vec3 vCameraPos; 18 | 19 | void main() { 20 | vNormal = normalize(normalMatrix * normal); 21 | vPos = modelViewMatrix * vec4(position, 1.0);; 22 | vColor = color; 23 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 24 | gl_Position = projectionMatrix * vPos; 25 | } -------------------------------------------------------------------------------- /src/shader/geometry_normal_map_100.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec2 uv; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | 9 | uniform mat3 normalMatrix; 10 | uniform mat4 modelMatrix; 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 viewMatrix; 13 | uniform mat4 projectionMatrix; 14 | uniform vec3 cameraPosition; 15 | 16 | varying vec2 vUv; 17 | varying vec3 vNormal; 18 | varying vec4 vColor; 19 | varying vec4 vPos; 20 | varying vec3 vCameraPos; 21 | 22 | void main() { 23 | vUv = uv; 24 | vNormal = normalize(normalMatrix * normal); 25 | vColor = color; 26 | vPos = modelViewMatrix * vec4(position, 1.0); 27 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 28 | 29 | gl_Position = projectionMatrix * vPos; 30 | } -------------------------------------------------------------------------------- /src/shader/geometry_normal_map_300.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | precision highp int; 4 | 5 | in vec3 position; 6 | in vec2 uv; 7 | in vec3 normal; 8 | in vec4 color; 9 | 10 | uniform mat3 normalMatrix; 11 | uniform mat4 modelMatrix; 12 | uniform mat4 modelViewMatrix; 13 | uniform mat4 viewMatrix; 14 | uniform mat4 projectionMatrix; 15 | uniform vec3 cameraPosition; 16 | 17 | out vec2 vUv; 18 | out vec3 vNormal; 19 | out vec4 vColor; 20 | out vec4 vPos; 21 | out vec3 vCameraPos; 22 | 23 | void main() { 24 | vUv = uv; 25 | vNormal = normalize(normalMatrix * normal); 26 | vColor = color; 27 | vPos = modelViewMatrix * vec4(position, 1.0); 28 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 29 | 30 | gl_Position = projectionMatrix * vPos; 31 | } -------------------------------------------------------------------------------- /src/shader/geometry_with_shadow.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec3 normal; 6 | attribute vec4 color; 7 | 8 | uniform mat4 modelMatrix; 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 viewMatrix; 11 | uniform mat4 projectionMatrix; 12 | uniform mat3 normalMatrix; 13 | 14 | uniform mat4 shadowViewMatrix; 15 | uniform mat4 shadowProjectionMatrix; 16 | uniform vec3 cameraPosition; 17 | 18 | varying vec3 vNormal; 19 | varying vec4 vColor; 20 | varying vec4 vLightNDC; 21 | varying vec4 vPos; 22 | varying vec3 vCameraPos; 23 | 24 | // Matrix to shift range from -1->1 to 0->1 25 | const mat4 depthScaleMatrix = mat4( 26 | 0.5, 0, 0, 0, 27 | 0, 0.5, 0, 0, 28 | 0, 0, 0.5, 0, 29 | 0.5, 0.5, 0.5, 1 30 | ); 31 | 32 | void main() { 33 | vNormal = normalize(normalMatrix * normal); 34 | vPos = modelViewMatrix * vec4(position, 1.0); 35 | vColor = color; 36 | vLightNDC = depthScaleMatrix * shadowProjectionMatrix * shadowViewMatrix * modelMatrix * vec4(position, 1.0); 37 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 38 | gl_Position = projectionMatrix * vPos; 39 | } -------------------------------------------------------------------------------- /src/shader/normal.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | varying vec3 vNormal; 5 | 6 | void main() { 7 | gl_FragColor.rgb = normalize(vNormal); 8 | gl_FragColor.a = 1.0; 9 | } -------------------------------------------------------------------------------- /src/shader/normal.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec3 normal; 6 | 7 | uniform mat3 normalMatrix; 8 | uniform mat4 modelViewMatrix; 9 | uniform mat4 projectionMatrix; 10 | 11 | varying vec3 vNormal; 12 | 13 | void main() { 14 | vNormal = normalize(normalMatrix * normal); 15 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 16 | } -------------------------------------------------------------------------------- /src/shader/polyline.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | varying vec4 vColor; 4 | 5 | void main() { 6 | gl_FragColor = vColor; 7 | } -------------------------------------------------------------------------------- /src/shader/polyline.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | attribute vec3 position; 3 | attribute vec3 next; 4 | attribute vec3 prev; 5 | attribute float side; 6 | attribute vec4 color; 7 | 8 | uniform mat4 modelViewMatrix; 9 | uniform mat4 projectionMatrix; 10 | uniform vec2 uResolution; 11 | uniform float uDPR; 12 | uniform float uThickness; 13 | uniform float uMiter; 14 | 15 | varying vec4 vColor; 16 | 17 | vec4 getPosition() { 18 | mat4 mvp = projectionMatrix * modelViewMatrix; 19 | vec4 current = mvp * vec4(position, 1); 20 | vec4 nextPos = mvp * vec4(next, 1); 21 | vec4 prevPos = mvp * vec4(prev, 1); 22 | vec2 aspect = vec2(uResolution.x / uResolution.y, 1); 23 | vec2 currentScreen = current.xy / current.w * aspect; 24 | vec2 nextScreen = nextPos.xy / nextPos.w * aspect; 25 | vec2 prevScreen = prevPos.xy / prevPos.w * aspect; 26 | 27 | vec2 dir1 = normalize(currentScreen - prevScreen); 28 | vec2 dir2 = normalize(nextScreen - currentScreen); 29 | vec2 dir = normalize(dir1 + dir2); 30 | 31 | vec2 normal = vec2(-dir.y, dir.x); 32 | normal /= mix(1.0, max(0.3, dot(normal, vec2(-dir1.y, dir1.x))), uMiter); 33 | normal /= aspect; 34 | float pixelWidthRatio = 1.0 / (uResolution.y / uDPR); 35 | float pixelWidth = current.w * pixelWidthRatio; 36 | normal *= pixelWidth * uThickness; 37 | current.xy -= normal * side; 38 | return current; 39 | } 40 | 41 | void main() { 42 | gl_Position = getPosition(); 43 | vColor = color; 44 | } -------------------------------------------------------------------------------- /src/shader/texture.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec3 normal; 6 | attribute vec4 color; 7 | attribute vec2 uv; 8 | 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 viewMatrix; 11 | uniform mat4 projectionMatrix; 12 | uniform mat3 normalMatrix; 13 | uniform vec3 cameraPosition; 14 | 15 | varying vec3 vNormal; 16 | varying vec4 vColor; 17 | varying vec2 vUv; 18 | varying vec4 vPos; 19 | varying vec3 vCameraPos; 20 | 21 | void main() { 22 | vNormal = normalize(normalMatrix * normal); 23 | vPos = modelViewMatrix * vec4(position, 1.0); 24 | vColor = color; 25 | vUv = uv; 26 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 27 | gl_Position = projectionMatrix * vPos; 28 | } -------------------------------------------------------------------------------- /src/shader/texture_cube.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec3 normal; 6 | attribute vec4 color; 7 | 8 | uniform mat4 modelViewMatrix; 9 | uniform mat4 viewMatrix; 10 | uniform mat4 projectionMatrix; 11 | uniform mat3 normalMatrix; 12 | uniform vec3 cameraPosition; 13 | 14 | varying vec3 vNormal; 15 | varying vec3 vDir; 16 | varying vec4 vColor; 17 | varying vec4 vPos; 18 | varying vec3 vCameraPos; 19 | 20 | void main() { 21 | vNormal = normalize(normalMatrix * normal); 22 | vPos = modelViewMatrix * vec4(position, 1.0); 23 | vDir = normalize(position); 24 | vColor = color; 25 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 26 | gl_Position = projectionMatrix * vPos; 27 | } -------------------------------------------------------------------------------- /src/shader/texture_normal_map_100.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec2 uv; 6 | attribute vec3 normal; 7 | attribute vec4 color; 8 | 9 | uniform mat3 normalMatrix; 10 | uniform mat4 modelMatrix; 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 viewMatrix; 13 | uniform mat4 projectionMatrix; 14 | uniform vec3 cameraPosition; 15 | 16 | varying vec2 vUv; 17 | varying vec3 vNormal; 18 | varying vec4 vColor; 19 | varying vec4 vPos; 20 | varying vec3 vCameraPos; 21 | 22 | void main() { 23 | vUv = uv; 24 | vNormal = normalize(normalMatrix * normal); 25 | vColor = color; 26 | vPos = modelViewMatrix * vec4(position, 1.0); 27 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 28 | 29 | gl_Position = projectionMatrix * vPos; 30 | } -------------------------------------------------------------------------------- /src/shader/texture_normal_map_300.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | precision highp int; 4 | 5 | in vec3 position; 6 | in vec2 uv; 7 | in vec3 normal; 8 | in vec4 color; 9 | 10 | uniform mat3 normalMatrix; 11 | uniform mat4 modelMatrix; 12 | uniform mat4 modelViewMatrix; 13 | uniform mat4 viewMatrix; 14 | uniform mat4 projectionMatrix; 15 | uniform vec3 cameraPosition; 16 | 17 | out vec2 vUv; 18 | out vec3 vNormal; 19 | out vec4 vColor; 20 | out vec4 vPos; 21 | out vec3 vCameraPos; 22 | 23 | void main() { 24 | vUv = uv; 25 | vNormal = normalize(normalMatrix * normal); 26 | vColor = color; 27 | vPos = modelViewMatrix * vec4(position, 1.0); 28 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 29 | 30 | gl_Position = projectionMatrix * vPos; 31 | } -------------------------------------------------------------------------------- /src/shader/texture_with_shadow.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | attribute vec3 position; 5 | attribute vec3 normal; 6 | attribute vec4 color; 7 | attribute vec2 uv; 8 | 9 | uniform mat4 modelMatrix; 10 | uniform mat4 modelViewMatrix; 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | uniform mat3 normalMatrix; 14 | uniform vec3 cameraPosition; 15 | 16 | varying vec3 vNormal; 17 | varying vec2 vUv; 18 | varying vec4 vColor; 19 | varying vec4 vLightNDC; 20 | varying vec4 vPos; 21 | varying vec3 vCameraPos; 22 | 23 | uniform mat4 shadowViewMatrix; 24 | uniform mat4 shadowProjectionMatrix; 25 | 26 | // Matrix to shift range from -1->1 to 0->1 27 | const mat4 depthScaleMatrix = mat4( 28 | 0.5, 0, 0, 0, 29 | 0, 0.5, 0, 0, 30 | 0, 0, 0.5, 0, 31 | 0.5, 0.5, 0.5, 1 32 | ); 33 | 34 | void main() { 35 | vNormal = normalize(normalMatrix * normal); 36 | vPos = modelViewMatrix * vec4(position, 1.0); 37 | vColor = color; 38 | vUv = uv; 39 | vLightNDC = depthScaleMatrix * shadowProjectionMatrix * shadowViewMatrix * modelMatrix * vec4(position, 1.0); 40 | vCameraPos = (viewMatrix * vec4(cameraPosition, 1.0)).xyz; 41 | gl_Position = projectionMatrix * vPos; 42 | } -------------------------------------------------------------------------------- /tools/data.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spritejs/sprite-extend-3d/1918e184c6a0effcad497e693772274b51e76231/tools/data.obj -------------------------------------------------------------------------------- /tools/obj-converter.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const OBJ = require('webgl-obj-loader'); 3 | 4 | const meshPath = './data.obj'; 5 | const opt = {encoding: 'utf8'}; 6 | 7 | fs.readFile(meshPath, opt, (err, data) => { 8 | if(err) return console.error(err); 9 | const mesh = new OBJ.Mesh(data); 10 | // console.log(JSON.stringify(mesh)); 11 | // console.log(Object.keys(mesh)); 12 | const geometry = { 13 | position: mesh.vertices, 14 | index: mesh.indices, 15 | normal: mesh.vertexNormals, 16 | uv: mesh.textures, 17 | }; 18 | let min = Infinity; 19 | let max = -Infinity; 20 | for(let i = 0; i < geometry.position.length; i++) { 21 | const n = geometry.position[i]; 22 | if(n < min) min = n; 23 | if(n > max) max = n; 24 | } 25 | const bound = Math.max(Math.abs(min), Math.abs(max)) / 3.0; 26 | for(let i = 0; i < geometry.position.length; i++) { 27 | geometry.position[i] /= bound; 28 | } 29 | fs.writeFileSync('./girl.json', JSON.stringify(geometry)); 30 | }); -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const EsmWebpackPlugin = require('@purtuga/esm-webpack-plugin'); 2 | const webpack = require('webpack'); 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const packageConfig = require('./package.json'); 6 | 7 | module.exports = function (env = {}) { 8 | let filename = env.module ? `${packageConfig.name}.esm` : `${packageConfig.name}`; 9 | if(env.mode === 'production') filename = `${filename}.min`; 10 | const output = { 11 | path: path.resolve(__dirname, env.outputPath || 'dist'), 12 | filename: `${filename}.js`, 13 | publicPath: '/js/', 14 | library: env.module ? 'ext3d' : { 15 | commonjs: 'sprite-extend-3d', 16 | amd: 'sprite-extend-3d', 17 | root: ['spritejs', 'ext3d'], 18 | }, 19 | libraryTarget: env.module ? 'var' : 'umd', 20 | globalObject: 'this', 21 | }; 22 | 23 | let babelConf; 24 | 25 | const babelRC = './.babelrc'; 26 | if(fs.existsSync(babelRC)) { 27 | babelConf = JSON.parse(fs.readFileSync(babelRC)); 28 | babelConf.babelrc = false; 29 | } 30 | 31 | const plugins = []; 32 | 33 | if(env.mode === 'development') { 34 | plugins.push(new webpack.HotModuleReplacementPlugin({ 35 | multiStep: true, 36 | })); 37 | } 38 | 39 | if(env.module) { 40 | plugins.push(new EsmWebpackPlugin()); 41 | plugins.push(new webpack.BannerPlugin({ 42 | banner: "import * as spritejs from 'https://unpkg.com/spritejs/dist/spritejs.esm.js';", 43 | raw: true, 44 | })); 45 | } 46 | 47 | return { 48 | mode: env.mode || 'none', 49 | entry: './src/index', 50 | output, 51 | // resolve: { 52 | // 53 | // }, 54 | 55 | module: { 56 | rules: [ 57 | { 58 | test: /\.js$/, 59 | exclude: /node_modules\/(?!ogl).*/, 60 | use: { 61 | loader: 'babel-loader', 62 | options: babelConf, 63 | }, 64 | }, 65 | { 66 | test: /\.(frag|vert|glsl)$/, 67 | use: { 68 | loader: 'raw-loader', 69 | options: {}, 70 | }, 71 | }, 72 | ], 73 | 74 | /* Advanced module configuration (click to show) */ 75 | }, 76 | 77 | externals: { 78 | spritejs: 'spritejs', 79 | }, 80 | // Don't follow/bundle these modules, but request them at runtime from the environment 81 | 82 | stats: 'errors-only', 83 | // lets you precisely control what bundle information gets displayed 84 | 85 | devServer: { 86 | contentBase: path.join(__dirname, env.server || '.'), 87 | compress: true, 88 | port: 3000, 89 | hot: true, 90 | // ... 91 | }, 92 | 93 | plugins, 94 | // list of additional plugins 95 | 96 | /* Advanced configuration (click to show) */ 97 | }; 98 | }; 99 | --------------------------------------------------------------------------------