├── .circleci └── config.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── codecov.yml ├── docs ├── examples │ ├── basic │ │ ├── index.html │ │ └── index.js │ ├── map │ │ ├── index.html │ │ ├── index.js │ │ └── uv_checker.png │ └── points │ │ ├── index.html │ │ └── index.js ├── images │ ├── thumbnail_basic.png │ ├── thumbnail_map.png │ └── thumbnail_points.png ├── index.css ├── index.html └── index.js ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── Camera.ts ├── Geometry.ts ├── Material.ts ├── Matrix4.ts ├── Mesh.ts ├── Object3D.ts ├── Points.ts ├── Quaternion.ts ├── Renderer.ts ├── Scene.ts ├── Vector3.ts ├── index.ts └── utils │ ├── __tests__ │ └── index.test.ts │ └── index.ts ├── tsconfig.json ├── tslint.json ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | 7 | defaults: &defaults 8 | working_directory: ~/repo 9 | docker: 10 | - image: circleci/node:10.16.0 11 | 12 | jobs: 13 | build: 14 | <<: *defaults 15 | steps: 16 | - checkout 17 | 18 | - restore_cache: 19 | keys: 20 | - v1-npm-deps-{{ checksum "package-lock.json" }} 21 | - v1-npm-deps- 22 | 23 | - run: npm ci 24 | - run: npm run build 25 | - save_cache: 26 | paths: 27 | - node_modules 28 | key: v1-npm-deps-{{ checksum "package-lock.json" }} 29 | 30 | - persist_to_workspace: 31 | root: ~/repo 32 | paths: . 33 | test: 34 | <<: *defaults 35 | steps: 36 | - attach_workspace: 37 | at: ~/repo 38 | - run: 39 | name: Run tests 40 | command: npm test 41 | deploy: 42 | <<: *defaults 43 | steps: 44 | - attach_workspace: 45 | at: ~/repo 46 | - run: 47 | name: Authenticate with registry 48 | command: echo "//registry.npmjs.org/:_authToken=$npm_TOKEN" > ~/repo/.npmrc 49 | - run: 50 | name: Publish package 51 | command: | 52 | echo "Bumping version to new tag: ${CIRCLE_TAG}" 53 | npm --no-git-tag-version version --allow-same-version $CIRCLE_TAG 54 | npm publish 55 | 56 | workflows: 57 | version: 2 58 | build-workflow: 59 | jobs: 60 | - build: 61 | filters: 62 | tags: 63 | only: /^v.*/ 64 | - test: 65 | requires: 66 | - build 67 | filters: 68 | tags: 69 | only: /^v.*/ 70 | - deploy: 71 | requires: 72 | - test 73 | filters: 74 | tags: 75 | only: /^v.*/ 76 | branches: 77 | ignore: /.*/ 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | coverage 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .prettierrc 2 | demo 3 | src 4 | README.md 5 | tsconfig.json 6 | tslint.json 7 | webpack.common.js 8 | webpack.dev.js 9 | webpack.prod.js 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Takayoshi Sawada 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shree.js 2 | 3 | [![CircleCI](https://circleci.com/gh/sawa-zen/shree/tree/master.svg?style=svg)](https://circleci.com/gh/sawa-zen/shree/tree/master) 4 | 5 | lite three.js 6 | 7 | [docs](https://sawa-zen.github.io/shree/) 8 | 9 | ## Install 10 | 11 | ``` 12 | $ npm install --save shree 13 | ``` 14 | 15 | or 16 | 17 | ```html 18 | 19 | ``` 20 | 21 | ## Usage 22 | 23 | 24 | 25 | ```c 26 | // vertex shader 27 | 28 | attribute vec3 position; 29 | attribute vec4 color; 30 | uniform mat4 pMatrix; 31 | uniform mat4 mvMatrix; 32 | varying vec4 vColor; 33 | 34 | void main(void){ 35 | vColor = color; 36 | gl_Position = pMatrix * mvMatrix * vec4(position, 1.0); 37 | } 38 | ``` 39 | 40 | ```c 41 | // fragment shader 42 | 43 | precision mediump float; 44 | varying vec4 vColor; 45 | 46 | void main(void){ 47 | gl_FragColor = vColor; 48 | } 49 | ``` 50 | 51 | ```javascript 52 | // sample.js 53 | 54 | var wrapper = document.getElementById('wrapper'); 55 | 56 | var renderer = new SHREE.Renderer(); 57 | renderer.setSize(wrapper.clientWidth, wrapper.clientHeight); 58 | wrapper.appendChild(renderer.domElement); 59 | 60 | var camera = new SHREE.Camera(); 61 | camera.position.z = 2; 62 | 63 | var scene = new SHREE.Scene(); 64 | 65 | var material = new SHREE.Material({ 66 | vertexShader: document.getElementById('vs').text, 67 | fragmentShader: document.getElementById('fs').text, 68 | }); 69 | 70 | var geometry = new SHREE.Geometry(); 71 | geometry.addAttribute('position', 3, [ 72 | 0.0, 0.5, 0.0, 73 | -1.0, -0.5, 0.0, 74 | 1.0, -0.5, 0.0, 75 | ]); 76 | geometry.addAttribute('color', 4, [ 77 | 1.0, 0.0, 0.0, 1.0, 78 | 0.0, 1.0, 0.0, 1.0, 79 | 0.0, 0.0, 1.0, 1.0, 80 | ]); 81 | geometry.index = [0, 1, 2]; 82 | 83 | var mesh = new SHREE.Mesh(geometry, material); 84 | scene.add(mesh); 85 | 86 | renderer.render(scene, camera); 87 | ``` 88 | 89 | ## Licence 90 | 91 | [MIT](https://github.com/sawa-zen/shree/blob/master/LICENSE) 92 | 93 | ## Author 94 | 95 | [sawa-zen](https://github.com/sawa-zen) 96 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "reach, diff, flags, files" 3 | behavior: default 4 | require_changes: false # if true: only post the comment if coverage changes 5 | require_base: no # [yes :: must have a base report to post] 6 | require_head: yes # [yes :: must have a head report to post] 7 | branches: null # branch names that can post comment 8 | -------------------------------------------------------------------------------- /docs/examples/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | shree.js demo basic 6 | 7 | 19 | 27 | 28 | 45 | 46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/examples/basic/index.js: -------------------------------------------------------------------------------- 1 | var wrapper = document.getElementById('wrapper'); 2 | 3 | var renderer = new SHREE.Renderer(); 4 | renderer.setSize(wrapper.clientWidth, wrapper.clientHeight); 5 | wrapper.appendChild(renderer.domElement); 6 | 7 | var camera = new SHREE.Camera(); 8 | camera.position.z = 2; 9 | 10 | var scene = new SHREE.Scene(); 11 | 12 | var material = new SHREE.Material({ 13 | vertexShader: document.getElementById('vs').text, 14 | fragmentShader: document.getElementById('fs').text, 15 | }); 16 | 17 | var geometry = new SHREE.Geometry(); 18 | geometry.addAttribute('position', 3, [ 19 | 0.0, 0.5, 0.0, 20 | -1.0, -0.5, 0.0, 21 | 1.0, -0.5, 0.0, 22 | ]); 23 | geometry.addAttribute('color', 4, [ 24 | 1.0, 0.0, 0.0, 1.0, 25 | 0.0, 1.0, 0.0, 1.0, 26 | 0.0, 0.0, 1.0, 1.0, 27 | ]); 28 | geometry.index = [0, 1, 2]; 29 | 30 | var mesh = new SHREE.Mesh(geometry, material); 31 | scene.add(mesh); 32 | 33 | renderer.render(scene, camera); 34 | -------------------------------------------------------------------------------- /docs/examples/map/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | shree.js demo map 6 | 7 | 22 | 31 | 32 | 55 | 56 |
57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/examples/map/index.js: -------------------------------------------------------------------------------- 1 | var img = new Image(); 2 | img.onload = function(event) { 3 | main(); 4 | } 5 | img.src = './uv_checker.png'; 6 | 7 | var main = function() { 8 | var count = 0; 9 | 10 | var wrapper = document.getElementById('wrapper'); 11 | 12 | // レンダラー 13 | var renderer = new SHREE.Renderer({ 14 | antialias: false, 15 | }); 16 | renderer.pixelRatio = 1 / 2; 17 | renderer.setSize(wrapper.clientWidth, wrapper.clientHeight); 18 | renderer.clearColor = [0.3, 0.3, 0.3, 1.0]; 19 | wrapper.appendChild(renderer.domElement); 20 | 21 | // カメラ 22 | var camera = new SHREE.Camera(); 23 | 24 | // シーン 25 | var scene = new SHREE.Scene(); 26 | 27 | // グループ 28 | var group = new SHREE.Object3D(); 29 | scene.add(group); 30 | 31 | // マテリアル 32 | var material = new SHREE.Material({ 33 | vertexShader: document.getElementById('vs').text, 34 | fragmentShader: document.getElementById('fs').text, 35 | uniforms: { texture: { type: 't', value: img } } 36 | }); 37 | 38 | // 八面体ジオメトリ 39 | var geometry1 = new SHREE.Geometry(); 40 | geometry1.addAttribute('position', 3, [ 41 | 0.0, 1.5, 0.0, 42 | 1.0, 0.0, 1.0, 43 | 1.0, 0.0, -1.0, 44 | -1.0, 0.0, -1.0, 45 | -1.0, 0.0, 1.0, 46 | 0.0, -1.5, 0.0, 47 | ]); 48 | geometry1.addAttribute('textureCoord', 2, [ 49 | 1.0, 0.0, 50 | 0.0, 0.0, 51 | 0.0, 1.0, 52 | 1.0, 1.0, 53 | 0.0, 1.0, 54 | 1.0, 0.0, 55 | ]); 56 | geometry1.index = [ 57 | 0, 1, 2, 58 | 0, 2, 3, 59 | 0, 3, 4, 60 | 0, 4, 1, 61 | 5, 2, 1, 62 | 5, 3, 2, 63 | 5, 4, 3, 64 | 5, 1, 4, 65 | ]; 66 | 67 | // 八面体メッシュ 68 | var octahedral = new SHREE.Mesh(geometry1, material); 69 | group.add(octahedral); 70 | 71 | // パネルジオメトリ 72 | var geometry2 = new SHREE.Geometry(); 73 | geometry2.addAttribute('position', 3, [ 74 | -25.0, -1.5, -25.0, 75 | 25.0, -1.5, -25.0, 76 | -25.0, -1.5, 25.0, 77 | 25.0, -1.5, 25.0, 78 | ]); 79 | geometry2.addAttribute('textureCoord', 2, [ 80 | 0.0, 0.0, 81 | 1.0, 0.0, 82 | 0.0, 1.0, 83 | 1.0, 1.0, 84 | ]); 85 | geometry2.index = [ 86 | 2, 1, 0, 87 | 3, 1, 2, 88 | ]; 89 | 90 | // パネルメッシュ 91 | var panel = new SHREE.Mesh(geometry2, material); 92 | group.add(panel); 93 | 94 | // 描画を始める 95 | var render = function() { 96 | count++; 97 | var rad = (count % 360) * Math.PI / 180; 98 | var rad2 = (count / 2 % 360) * Math.PI / 180; 99 | octahedral.rotation.y = -rad * 4; 100 | octahedral.position.x = Math.sin(rad) * 5; 101 | octahedral.position.z = Math.cos(rad) * 5; 102 | camera.rotation.y = -rad2; 103 | 104 | if (count % 2) { 105 | renderer.render(scene, camera); 106 | } 107 | requestAnimationFrame(render); 108 | } 109 | render(); 110 | } 111 | -------------------------------------------------------------------------------- /docs/examples/map/uv_checker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sawa-zen/shree/8bb60c9af9b9105f25c6960fb428264f32915f78/docs/examples/map/uv_checker.png -------------------------------------------------------------------------------- /docs/examples/points/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | shree.js demo points 6 | 7 | 23 | 31 | 32 | 55 | 56 |
57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/examples/points/index.js: -------------------------------------------------------------------------------- 1 | var main = function() { 2 | var count = 0; 3 | 4 | var wrapper = document.getElementById('wrapper'); 5 | 6 | // レンダラー 7 | var renderer = new SHREE.Renderer({ 8 | antialias: false, 9 | }); 10 | renderer.pixelRatio = 1 / 2; 11 | renderer.setSize(wrapper.clientWidth, wrapper.clientHeight); 12 | renderer.clearColor = [0.3, 0.3, 0.3, 1.0]; 13 | wrapper.appendChild(renderer.domElement); 14 | 15 | // カメラ 16 | var camera = new SHREE.Camera(); 17 | camera.position.z = 5; 18 | camera.position.y = 2; 19 | camera.rotation.x = -0.3; 20 | 21 | // シーン 22 | var scene = new SHREE.Scene(); 23 | 24 | // グループ 25 | var group = new SHREE.Object3D(); 26 | scene.add(group); 27 | 28 | // マテリアル 29 | var material = new SHREE.Material({ 30 | vertexShader: document.getElementById('vs').text, 31 | fragmentShader: document.getElementById('fs').text, 32 | }); 33 | 34 | // 八面体ジオメトリ 35 | var geometry1 = new SHREE.Geometry(); 36 | geometry1.addAttribute('position', 3, [ 37 | 0.0, 1.5, 0.0, 38 | 1.0, 0.0, 1.0, 39 | 1.0, 0.0, -1.0, 40 | -1.0, 0.0, -1.0, 41 | -1.0, 0.0, 1.0, 42 | 0.0, -1.5, 0.0, 43 | ]); 44 | geometry1.addAttribute('color', 4, [ 45 | 1.0, 0.0, 0.0, 1.0, 46 | 0.0, 1.0, 0.0, 1.0, 47 | 0.0, 0.0, 1.0, 1.0, 48 | 1.0, 1.0, 0.0, 1.0, 49 | 1.0, 0.0, 1.0, 1.0, 50 | 0.0, 1.0, 1.0, 1.0, 51 | ]); 52 | geometry1.index = [ 53 | 0, 1, 2, 54 | 0, 2, 3, 55 | 0, 3, 4, 56 | 0, 4, 1, 57 | 5, 2, 1, 58 | 5, 3, 2, 59 | 5, 4, 3, 60 | 5, 1, 4, 61 | ]; 62 | 63 | // 八面体ポイント 64 | var point = new SHREE.Points(geometry1, material); 65 | point.position.x = 2; 66 | group.add(point); 67 | 68 | // 八面体メッシュ 69 | var mesh = new SHREE.Mesh(geometry1, material); 70 | mesh.position.x = -2; 71 | group.add(mesh); 72 | 73 | // 描画を始める 74 | var render = function() { 75 | count++; 76 | var rad = (count % 360) * Math.PI / 180; 77 | point.rotation.x = -rad; 78 | point.rotation.y = -rad; 79 | mesh.rotation.x = -rad; 80 | mesh.rotation.y = -rad; 81 | 82 | if (count % 2) { 83 | renderer.render(scene, camera); 84 | } 85 | requestAnimationFrame(render); 86 | } 87 | render(); 88 | } 89 | main(); 90 | -------------------------------------------------------------------------------- /docs/images/thumbnail_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sawa-zen/shree/8bb60c9af9b9105f25c6960fb428264f32915f78/docs/images/thumbnail_basic.png -------------------------------------------------------------------------------- /docs/images/thumbnail_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sawa-zen/shree/8bb60c9af9b9105f25c6960fb428264f32915f78/docs/images/thumbnail_map.png -------------------------------------------------------------------------------- /docs/images/thumbnail_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sawa-zen/shree/8bb60c9af9b9105f25c6960fb428264f32915f78/docs/images/thumbnail_points.png -------------------------------------------------------------------------------- /docs/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | font-family: 'Lato', sans-serif; 5 | color: #666; 6 | } 7 | 8 | .background { 9 | position: fixed; 10 | top: 0; 11 | right: 0; 12 | left: 0; 13 | bottom: 0; 14 | z-index: -1; 15 | } 16 | 17 | aside { 18 | position: fixed; 19 | top: 0; 20 | left: 0; 21 | bottom: 0; 22 | width: 240px; 23 | padding: 36px; 24 | box-sizing: border-box; 25 | background-color: rgba(255, 255, 255, 0.7); 26 | } 27 | 28 | aside h1 { 29 | font-size: 24px; 30 | padding: 0 0 24px 0; 31 | } 32 | 33 | aside ul { 34 | list-style: none; 35 | } 36 | 37 | aside ul li { 38 | margin-top: 24px; 39 | } 40 | 41 | aside ul li:first-child { 42 | margin-top: 0; 43 | } 44 | 45 | aside .GitHub { 46 | display: block; 47 | margin-top: 48px; 48 | } 49 | 50 | main { 51 | width: 100%; 52 | height: 100%; 53 | padding-left: 240px; 54 | padding-bottom: 24px; 55 | box-sizing: border-box; 56 | } 57 | 58 | section { 59 | display: flex; 60 | flex-direction: column; 61 | padding: 36px; 62 | } 63 | 64 | section > * { 65 | margin-top: 24px; 66 | } 67 | 68 | section > h2 { 69 | padding: 0; 70 | } 71 | 72 | .Demo { 73 | width: 300px; 74 | height: 200px; 75 | margin-left: 8px; 76 | } 77 | 78 | .Demo:first-child { 79 | margin-left: 0; 80 | } 81 | 82 | .Demos__list { 83 | display: flex; 84 | } 85 | 86 | pre { 87 | border: 1px solid #CCC; 88 | border-radius: 5px; 89 | padding: 18px; 90 | background-color: rgba(255, 255, 255, 0.7); 91 | } 92 | 93 | pre:first-child { 94 | margin-top: 0; 95 | } 96 | 97 | .API__Section { 98 | border: 1px solid #ccc; 99 | border-radius: 5px; 100 | margin-top: 24px; 101 | padding: 16px; 102 | background-color: rgba(255, 255, 255, 0.7); 103 | } 104 | 105 | .API__Section:first-child { 106 | margin-top: 0; 107 | } 108 | 109 | .API__SectionBodyChild { 110 | margin-top: 24px; 111 | } 112 | 113 | .API__SectionBodyChild h4{ 114 | color: #4DB5C8; 115 | } 116 | 117 | .API__SectionBodyChild h5{ 118 | margin-top: 16px; 119 | } 120 | 121 | .API__SectionBodyList { 122 | margin-top: 16px; 123 | list-style: none; 124 | } 125 | 126 | .API__SectionBodyList li { 127 | margin-top: 8px; 128 | } 129 | 130 | .API__SectionBodyList li:first-child { 131 | margin-top: 0; 132 | } 133 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | shree.js - Javascript 3D library 6 | 7 | 8 | 9 | 10 | 31 | 39 | 40 | 41 |
42 | 51 |
52 |
53 |

Demos

54 |
55 | map 56 | points 57 |
58 |
59 |
60 |

Install

61 |
$ npm install --save shree
62 |
or
63 |
<script src="https://unpkg.com/shree/dist/shree.js"></script>
64 |
65 |
66 |

Basic Usage

67 |
68 | basic 69 |
70 |
// vertex shader
 71 | 
 72 | attribute vec3 position;
 73 | attribute vec4 color;
 74 | uniform mat4 pMatrix;
 75 | uniform mat4 mvMatrix;
 76 | varying vec4 vColor;
 77 | 
 78 | void main(void){
 79 |   vColor = color;
 80 |   gl_Position = pMatrix * mvMatrix * vec4(position, 1.0);
 81 | }
82 |
// fragment shader
 83 | 
 84 | precision mediump float;
 85 | varying vec4 vColor;
 86 | 
 87 | void main(void){
 88 |   gl_FragColor = vColor;
 89 | }
90 |
// sample.js
 91 | 
 92 | var wrapper = document.getElementById('wrapper');
 93 | 
 94 | var renderer = new SHREE.Renderer();
 95 | renderer.setSize(wrapper.clientWidth, wrapper.clientHeight);
 96 | wrapper.appendChild(renderer.domElement);
 97 | 
 98 | var camera = new SHREE.Camera();
 99 | camera.position.z = 2;
100 | 
101 | var scene = new SHREE.Scene();
102 | 
103 | var material = new SHREE.Material({
104 |   vertexShader: document.getElementById('vs').text,
105 |   fragmentShader: document.getElementById('fs').text,
106 | });
107 | 
108 | var geometry = new SHREE.Geometry();
109 | geometry.addAttribute('position', 3, [
110 |    0.0,  0.5,  0.0,
111 |   -1.0, -0.5,  0.0,
112 |    1.0, -0.5,  0.0,
113 | ]);
114 | geometry.addAttribute('color', 4, [
115 |   1.0, 0.0, 0.0, 1.0,
116 |   0.0, 1.0, 0.0, 1.0,
117 |   0.0, 0.0, 1.0, 1.0,
118 | ]);
119 | geometry.index = [0, 1, 2];
120 | 
121 | var mesh = new SHREE.Mesh(geometry, material);
122 | scene.add(mesh);
123 | 
124 | renderer.render(scene, camera);
125 |
126 |
127 |

API

128 |
129 |
130 |

Renderer

131 |
132 |
133 |

Constructor

134 |
Renderer(parameters: object)
135 |
    136 |
  • antialias: boolean - whether to perform antialiasing. Default is false.
  • 137 |
138 |
139 |
140 |

Properties

141 |
    142 |
  • pixelRatio: number
  • 143 |
  • domElement: HTMLDivElement
  • 144 |
  • clearColor: number[]
  • 145 |
146 |
147 |
148 |

Methods

149 |
    150 |
  • setSize(width: number, height: number): void
  • 151 |
  • render(scene: Scene, camera: Camera): void
  • 152 |
153 |
154 |
155 |
156 |
157 |

Vector3

158 |
159 |
160 |

Constructor

161 |
Vector3(x: number = 0, y: number = 0, z: number = 0)
162 |
163 |
164 |

Properties

165 |
    166 |
  • x: number
  • 167 |
  • y: number
  • 168 |
  • z: number
  • 169 |
170 |
171 |
172 |
173 |
174 |

Quaternion

175 |
176 |
177 |

Constructor

178 |
Quaternion(x: number = 0, y: number = 0, z: number = 0, w: number = 0)
179 |
180 |
181 |

Properties

182 |
    183 |
  • x: number
  • 184 |
  • y: number
  • 185 |
  • z: number
  • 186 |
  • w: number
  • 187 |
188 |
189 |
190 |

Methods

191 |
    192 |
  • setFromEuler(euler: Vector3): Quaternion
  • 193 |
194 |
195 |
196 |
197 |
198 |

Object3D

199 |
200 |
201 |

Constructor

202 |
Object3D()
203 |
204 |
205 |

Properties

206 |
    207 |
  • id: string
  • 208 |
  • position: Vector3
  • 209 |
  • up: Vector3
  • 210 |
  • scale: vector3
  • 211 |
  • rotation: Vector3
  • 212 |
  • quaternion: Quaternion
  • 213 |
  • parent: Object3D | null
  • 214 |
  • children: Object3D[]
  • 215 |
  • matrix: Matrix4
  • 216 |
  • matrixWorld: Matrix4
  • 217 |
  • modelViewMatrix: Matrix4
  • 218 |
219 |
220 |
221 |

Methods

222 |
    223 |
  • add(obj: Object3D): void
  • 224 |
  • updateMatrix(): void
  • 225 |
  • updateMatrixWorld(): void
  • 226 |
227 |
228 |
229 |
230 |
231 |

Camera < Object3D

232 |
233 |
234 |

Constructor

235 |
Camera()
236 |
237 |
238 |

Properties

239 |
    240 |
  • matrixWorldInverse: Matrix4
  • 241 |
242 |
243 |
244 |

Methods

245 |
    246 |
  • updateMatrixWorld(): void
  • 247 |
248 |
249 |
250 |
251 |
252 |

Scene < Object3D

253 |
254 |
255 |

Constructor

256 |
Scene()
257 |
258 |
259 |

Properties

260 |
    261 |
  • needsUpdate: boolean
  • 262 |
263 |
264 |
265 |
266 |
267 |

Mesh < Object3D

268 |
269 |
270 |

Constructor

271 |
Mesh(geometry: Geometry, material: Material)
272 |
273 |
274 |

Properties

275 |
    276 |
  • geometry: Geometry
  • 277 |
  • material: Material
  • 278 |
279 |
280 |
281 |
282 |
283 |

Geometry

284 |
285 |
286 |

Constructor

287 |
Geometry()
288 |
289 |
290 |

Properties

291 |
    292 |
  • attribute: { [name: string]: { stride: number; vertices: number[]; } }
  • 293 |
  • index: number[]
  • 294 |
295 |
296 |
297 |

Methods

298 |
    299 |
  • addAttribute(name: string, stride: number, vertices: number[]): void
  • 300 |
301 |
302 |
303 |
304 |
305 |

Material

306 |
307 |
308 |

Constructor

309 |
Material(parameters: object)
310 |
    311 |
  • uniforms: { [name: string]: { type: 'v4' | 't', value: Matrix4 | HTMLImageElement } }
  • 312 |
  • vertexShader: string
  • 313 |
  • fragmentShader: string
  • 314 |
  • transparent: boolean
  • 315 |
  • side: 'SIDE_FRONT' | 'SIDE_BACK' | 'SIDE_DOUBLE'
  • 316 |
317 |
318 |
319 |
320 |
321 |

Points < Object3D

322 |
323 |
324 |

Constructor

325 |
Points(geometry: Geometry, material: Material)
326 |
327 |
328 |

Properties

329 |
    330 |
  • geometry: Geometry
  • 331 |
  • material: Material
  • 332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 | 340 | 341 | 342 | -------------------------------------------------------------------------------- /docs/index.js: -------------------------------------------------------------------------------- 1 | var main = function() { 2 | var count = 0; 3 | 4 | var wrapper = document.getElementById('background'); 5 | 6 | // レンダラー 7 | var renderer = new SHREE.Renderer({ antialias: true }); 8 | renderer.pixelRatio = 1; 9 | renderer.clearColor = [1.0, 1.0, 1.0, 1.0]; 10 | renderer.setSize(wrapper.clientWidth, wrapper.clientHeight); 11 | wrapper.appendChild(renderer.domElement); 12 | 13 | // カメラ 14 | var camera = new SHREE.Camera(); 15 | camera.position.y = 10; 16 | camera.position.z = 40; 17 | camera.rotation.x = -1; 18 | 19 | // シーン 20 | var scene = new SHREE.Scene(); 21 | 22 | var material = new SHREE.Material({ 23 | vertexShader: document.getElementById('vs').text, 24 | fragmentShader: document.getElementById('fs').text, 25 | uniforms: { 26 | time: { 27 | type: 'f', 28 | value: 0, 29 | } 30 | }, 31 | transparent: true 32 | }); 33 | 34 | var geometry = new SHREE.Geometry(); 35 | var position = []; 36 | var seed = []; 37 | var absolute = 90; 38 | for (var z = -absolute; z < absolute; z++) { 39 | for (var x = -absolute; x < absolute; x++) { 40 | position.push(x); // x 41 | position.push(0); // y 42 | position.push(z); // z 43 | seed.push(z + x); 44 | } 45 | } 46 | geometry.addAttribute('position', 3, position); 47 | geometry.addAttribute('seed', 1, seed); 48 | 49 | var points = new SHREE.Points(geometry, material); 50 | scene.add(points); 51 | 52 | // 描画を始める 53 | var render = function() { 54 | points.rotation.y += 0.003; 55 | material.uniforms.time.value += 0.5; 56 | renderer.render(scene, camera); 57 | requestAnimationFrame(render); 58 | } 59 | render(); 60 | } 61 | main(); 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shree", 3 | "version": "0.1.13", 4 | "description": "lite three.js", 5 | "main": "dist/shree.js", 6 | "sideEffects": false, 7 | "scripts": { 8 | "start": "webpack --config webpack.dev.js --watch", 9 | "build": "webpack --config webpack.prod.js --display-used-exports", 10 | "test": "jest && codecov", 11 | "lint": "tslint -c tslint.json -p tsconfig.json", 12 | "lint:fix": "npm run lint -- --fix", 13 | "precommit": "lint-staged" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/sawa-zen/shree.git" 18 | }, 19 | "keywords": [ 20 | "three.js" 21 | ], 22 | "lint-staged": { 23 | "*.ts": [ 24 | "npm run lint:fix", 25 | "git add" 26 | ] 27 | }, 28 | "author": "sawa-zen", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/sawa-zen/shree/issues" 32 | }, 33 | "homepage": "https://github.com/sawa-zen/shree#readme", 34 | "dependencies": { 35 | "eventemitter3": "^3.1.0" 36 | }, 37 | "devDependencies": { 38 | "@types/jest": "24.0.15", 39 | "@types/webpack": "4.4.32", 40 | "codecov": "3.5.0", 41 | "fork-ts-checker-webpack-plugin": "1.3.7", 42 | "husky": "2.4.1", 43 | "jest": "24.7.1", 44 | "jest-canvas-mock": "2.1.0", 45 | "lint-staged": "8.2.1", 46 | "prettier": "1.18.2", 47 | "ts-jest": "24.0.2", 48 | "ts-loader": "6.0.2", 49 | "tslint": "5.17.0", 50 | "tslint-config-prettier": "1.18.0", 51 | "tslint-plugin-prettier": "2.0.1", 52 | "typescript": "3.5.2", 53 | "uglifyjs-webpack-plugin": "2.1.3", 54 | "webpack": "4.34.0", 55 | "webpack-cli": "3.3.4", 56 | "webpack-merge": "4.2.1" 57 | }, 58 | "jest": { 59 | "moduleFileExtensions": [ 60 | "ts", 61 | "tsx", 62 | "js" 63 | ], 64 | "transform": { 65 | "^.+\\.(ts|tsx)$": "ts-jest" 66 | }, 67 | "setupFiles": [ 68 | "jest-canvas-mock" 69 | ], 70 | "globals": { 71 | "ts-jest": { 72 | "tsConfig": "tsconfig.json" 73 | } 74 | }, 75 | "testMatch": [ 76 | "**/__tests__/*.+(ts|tsx|js)" 77 | ], 78 | "collectCoverage": true 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/Camera.ts: -------------------------------------------------------------------------------- 1 | import Object3D from './Object3D'; 2 | import Matrix4 from './Matrix4'; 3 | 4 | class Camera extends Object3D { 5 | private _matrixWorldInverse: Matrix4 = new Matrix4(); 6 | get matrixWorldInverse() { 7 | return this._matrixWorldInverse; 8 | } 9 | 10 | public updateMatrixWorld() { 11 | super.updateMatrixWorld(); 12 | this.matrixWorldInverse.getInverse(this.matrixWorld); 13 | } 14 | } 15 | 16 | export default Camera; 17 | -------------------------------------------------------------------------------- /src/Geometry.ts: -------------------------------------------------------------------------------- 1 | interface Attribute { 2 | stride: number; 3 | verticies: number[]; 4 | } 5 | 6 | interface Attributes { 7 | [name: string]: Attribute; 8 | } 9 | 10 | class Geometry { 11 | _attributes: Attributes = {}; 12 | get attributes() { 13 | return this._attributes; 14 | } 15 | 16 | _index: number[] = []; 17 | get index() { 18 | return this._index; 19 | } 20 | set index(index: number[]) { 21 | this._index = index; 22 | } 23 | 24 | addAttribute(name: string, stride: number, verticies: number[]) { 25 | this._attributes[name] = { stride, verticies }; 26 | } 27 | } 28 | 29 | export default Geometry; 30 | -------------------------------------------------------------------------------- /src/Material.ts: -------------------------------------------------------------------------------- 1 | import Matrix4 from './Matrix4'; 2 | import { Side } from './utils'; 3 | 4 | interface V4Uniform { 5 | type: 'v4'; 6 | value: Matrix4; 7 | } 8 | 9 | interface TUniform { 10 | type: 't'; 11 | value: HTMLImageElement; 12 | } 13 | 14 | interface FUniform { 15 | type: 'f'; 16 | value: number; 17 | } 18 | 19 | interface Uniforms { 20 | [name: string]: V4Uniform | TUniform | FUniform; 21 | } 22 | 23 | enum Blending { 24 | NO = 'BLENDING_NO' 25 | } 26 | 27 | interface Props { 28 | uniforms?: Uniforms; 29 | vertexShader: string; 30 | fragmentShader: string; 31 | transparent?: boolean; 32 | side: Side; 33 | blending: Blending; 34 | } 35 | 36 | class Material { 37 | private _uniforms: Uniforms = { 38 | mMatrix: { 39 | type: 'v4', 40 | value: new Matrix4() 41 | }, 42 | vMatrix: { 43 | type: 'v4', 44 | value: new Matrix4() 45 | }, 46 | pMatrix: { 47 | type: 'v4', 48 | value: new Matrix4() 49 | }, 50 | mvMatrix: { 51 | type: 'v4', 52 | value: new Matrix4() 53 | } 54 | }; 55 | get uniforms() { 56 | return this._uniforms; 57 | } 58 | 59 | private _vertexShader: string; 60 | get vertexShader() { 61 | return this._vertexShader; 62 | } 63 | 64 | private _fragmentShader: string; 65 | get fragmentShader() { 66 | return this._fragmentShader; 67 | } 68 | 69 | private _transparent: boolean = false; 70 | get transparent() { 71 | return this._transparent; 72 | } 73 | 74 | private _side: Side = Side.FRONT; 75 | get side() { 76 | return this._side; 77 | } 78 | 79 | private _blending: Blending = Blending.NO; 80 | get blending() { 81 | return this._blending; 82 | } 83 | 84 | constructor(props: Props) { 85 | this._uniforms = { 86 | ...this._uniforms, 87 | ...props.uniforms 88 | }; 89 | this._vertexShader = props.vertexShader; 90 | this._fragmentShader = props.fragmentShader; 91 | this._transparent = props.transparent || false; 92 | this._side = props.side || this._side; 93 | this._blending = props.blending || 'BLENDING_NO'; 94 | } 95 | } 96 | 97 | export default Material; 98 | -------------------------------------------------------------------------------- /src/Matrix4.ts: -------------------------------------------------------------------------------- 1 | import Quaternion from './Quaternion'; 2 | import Vector3 from './Vector3'; 3 | 4 | /** 5 | * Matrix4 6 | */ 7 | class Matrix4 { 8 | public _el: Float32Array = new Float32Array(16); 9 | get el() { 10 | return this._el; 11 | } 12 | 13 | constructor() { 14 | this.identity(); 15 | } 16 | 17 | public identity() { 18 | this._el[0] = 1; 19 | this._el[1] = 0; 20 | this._el[2] = 0; 21 | this._el[3] = 0; 22 | 23 | this._el[4] = 0; 24 | this._el[5] = 1; 25 | this._el[6] = 0; 26 | this._el[7] = 0; 27 | 28 | this._el[8] = 0; 29 | this._el[9] = 0; 30 | this._el[10] = 1; 31 | this._el[11] = 0; 32 | 33 | this._el[12] = 0; 34 | this._el[13] = 0; 35 | this._el[14] = 0; 36 | this._el[15] = 1; 37 | 38 | return this; 39 | } 40 | 41 | public multiply(mat: Matrix4): Matrix4 { 42 | this.multiplyMatrices(this, mat); 43 | return this; 44 | } 45 | 46 | public multiplyMatrices(aMat: Matrix4, bMat: Matrix4): Matrix4 { 47 | const aEl = aMat.el; 48 | const bEl = bMat.el; 49 | 50 | const a = aEl[0], 51 | b = aEl[1], 52 | c = aEl[2], 53 | d = aEl[3], 54 | e = aEl[4], 55 | f = aEl[5], 56 | g = aEl[6], 57 | h = aEl[7], 58 | i = aEl[8], 59 | j = aEl[9], 60 | k = aEl[10], 61 | l = aEl[11], 62 | m = aEl[12], 63 | n = aEl[13], 64 | o = aEl[14], 65 | p = aEl[15]; 66 | 67 | const A = bEl[0], 68 | B = bEl[1], 69 | C = bEl[2], 70 | D = bEl[3], 71 | E = bEl[4], 72 | F = bEl[5], 73 | G = bEl[6], 74 | H = bEl[7], 75 | I = bEl[8], 76 | J = bEl[9], 77 | K = bEl[10], 78 | L = bEl[11], 79 | M = bEl[12], 80 | N = bEl[13], 81 | O = bEl[14], 82 | P = bEl[15]; 83 | 84 | this._el[0] = A * a + B * e + C * i + D * m; 85 | this._el[1] = A * b + B * f + C * j + D * n; 86 | this._el[2] = A * c + B * g + C * k + D * o; 87 | this._el[3] = A * d + B * h + C * l + D * p; 88 | 89 | this._el[4] = E * a + F * e + G * i + H * m; 90 | this._el[5] = E * b + F * f + G * j + H * n; 91 | this._el[6] = E * c + F * g + G * k + H * o; 92 | this._el[7] = E * d + F * h + G * l + H * p; 93 | 94 | this._el[8] = I * a + J * e + K * i + L * m; 95 | this._el[9] = I * b + J * f + K * j + L * n; 96 | this._el[10] = I * c + J * g + K * k + L * o; 97 | this._el[11] = I * d + J * h + K * l + L * p; 98 | 99 | this._el[12] = M * a + N * e + O * i + P * m; 100 | this._el[13] = M * b + N * f + O * j + P * n; 101 | this._el[14] = M * c + N * g + O * k + P * o; 102 | this._el[15] = M * d + N * h + O * l + P * p; 103 | 104 | return this; 105 | } 106 | 107 | /** 108 | * 渡されたベクトル分拡大縮小する 109 | */ 110 | public scale(vec: number[]) { 111 | this._el[0] = this._el[0] * vec[0]; 112 | this._el[1] = this._el[1] * vec[0]; 113 | this._el[2] = this._el[2] * vec[0]; 114 | this._el[3] = this._el[3] * vec[0]; 115 | 116 | this._el[4] = this._el[4] * vec[1]; 117 | this._el[5] = this._el[5] * vec[1]; 118 | this._el[6] = this._el[6] * vec[1]; 119 | this._el[7] = this._el[7] * vec[1]; 120 | 121 | this._el[8] = this._el[8] * vec[2]; 122 | this._el[9] = this._el[9] * vec[2]; 123 | this._el[10] = this._el[10] * vec[2]; 124 | this._el[11] = this._el[11] * vec[2]; 125 | 126 | return this; 127 | } 128 | 129 | public translate(vec3: number[]) { 130 | this._el[12] = 131 | this._el[0] * vec3[0] + 132 | this._el[4] * vec3[1] + 133 | this._el[8] * vec3[2] + 134 | this._el[12]; 135 | this._el[13] = 136 | this._el[1] * vec3[0] + 137 | this._el[5] * vec3[1] + 138 | this._el[9] * vec3[2] + 139 | this._el[13]; 140 | this._el[14] = 141 | this._el[2] * vec3[0] + 142 | this._el[6] * vec3[1] + 143 | this._el[10] * vec3[2] + 144 | this._el[14]; 145 | this._el[15] = 146 | this._el[3] * vec3[0] + 147 | this._el[7] * vec3[1] + 148 | this._el[11] * vec3[2] + 149 | this._el[15]; 150 | 151 | return this; 152 | } 153 | 154 | public rotate(angle: number, axis: number[]) { 155 | let sq = Math.sqrt( 156 | axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2] 157 | ); 158 | 159 | if (!sq) { 160 | return; 161 | } 162 | 163 | let a = axis[0], 164 | b = axis[1], 165 | c = axis[2]; 166 | 167 | if (sq !== 1) { 168 | sq = 1 / sq; 169 | a *= sq; 170 | b *= sq; 171 | c *= sq; 172 | } 173 | 174 | const d = Math.sin(angle), 175 | e = Math.cos(angle), 176 | f = 1 - e, 177 | g = this._el[0], 178 | h = this._el[1], 179 | i = this._el[2], 180 | j = this._el[3], 181 | k = this._el[4], 182 | l = this._el[5], 183 | m = this._el[6], 184 | n = this._el[7], 185 | o = this._el[8], 186 | p = this._el[9], 187 | q = this._el[10], 188 | r = this._el[11], 189 | s = a * a * f + e, 190 | t = b * a * f + c * d, 191 | u = c * a * f - b * d, 192 | v = a * b * f - c * d, 193 | w = b * b * f + e, 194 | x = c * b * f + a * d, 195 | y = a * c * f + b * d, 196 | z = b * c * f - a * d, 197 | A = c * c * f + e; 198 | 199 | this._el[0] = g * s + k * t + o * u; 200 | this._el[1] = h * s + l * t + p * u; 201 | this._el[2] = i * s + m * t + q * u; 202 | this._el[3] = j * s + n * t + r * u; 203 | 204 | this._el[4] = g * v + k * w + o * x; 205 | this._el[5] = h * v + l * w + p * x; 206 | this._el[6] = i * v + m * w + q * x; 207 | this._el[7] = j * v + n * w + r * x; 208 | 209 | this._el[8] = g * y + k * z + o * A; 210 | this._el[9] = h * y + l * z + p * A; 211 | this._el[10] = i * y + m * z + q * A; 212 | this._el[11] = j * y + n * z + r * A; 213 | 214 | return this; 215 | } 216 | 217 | /** 218 | * ビュー変換行列を生成する 219 | */ 220 | public lookAt(eye: Vector3, center: Vector3, up: Vector3) { 221 | const eyeX = eye.x, 222 | eyeY = eye.y, 223 | eyeZ = eye.z, 224 | upX = up.x, 225 | upY = up.y, 226 | upZ = up.z, 227 | centerX = center.x, 228 | centerY = center.y, 229 | centerZ = center.z; 230 | 231 | if (eyeX === centerX && eyeY === centerY && eyeZ === centerZ) { 232 | this.identity(); 233 | return; 234 | } 235 | 236 | let x0, x1, x2, y0, y1, y2, z0, z1, z2, l; 237 | z0 = eyeX - center.x; 238 | z1 = eyeY - center.y; 239 | z2 = eyeZ - center.z; 240 | l = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); 241 | z0 *= l; 242 | z1 *= l; 243 | z2 *= l; 244 | x0 = upY * z2 - upZ * z1; 245 | x1 = upZ * z0 - upX * z2; 246 | x2 = upX * z1 - upY * z0; 247 | l = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); 248 | 249 | if (!l) { 250 | x0 = 0; 251 | x1 = 0; 252 | x2 = 0; 253 | } else { 254 | l = 1 / l; 255 | x0 *= l; 256 | x1 *= l; 257 | x2 *= l; 258 | } 259 | 260 | y0 = z1 * x2 - z2 * x1; 261 | y1 = z2 * x0 - z0 * x2; 262 | y2 = z0 * x1 - z1 * x0; 263 | l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); 264 | 265 | if (!l) { 266 | y0 = 0; 267 | y1 = 0; 268 | y2 = 0; 269 | } else { 270 | l = 1 / l; 271 | y0 *= l; 272 | y1 *= l; 273 | y2 *= l; 274 | } 275 | 276 | this._el[0] = x0; 277 | this._el[1] = y0; 278 | this._el[2] = z0; 279 | this._el[3] = 0; 280 | 281 | this._el[4] = x1; 282 | this._el[5] = y1; 283 | this._el[6] = z1; 284 | this._el[7] = 0; 285 | 286 | this._el[8] = x2; 287 | this._el[9] = y2; 288 | this._el[10] = z2; 289 | this._el[11] = 0; 290 | 291 | this._el[12] = -(x0 * eyeX + x1 * eyeY + x2 * eyeZ); 292 | this._el[13] = -(y0 * eyeX + y1 * eyeY + y2 * eyeZ); 293 | this._el[14] = -(z0 * eyeX + z1 * eyeY + z2 * eyeZ); 294 | this._el[15] = 1; 295 | 296 | return this; 297 | } 298 | 299 | /** 300 | * プロジェクション変換行列を生成する 301 | */ 302 | public perspective(fovy: number, aspect: number, near: number, far: number) { 303 | const t = near * Math.tan((fovy * Math.PI) / 360); 304 | const r = t * aspect; 305 | const a = r * 2, 306 | b = t * 2, 307 | c = far - near; 308 | 309 | this._el[0] = (near * 2) / a; 310 | this._el[1] = 0; 311 | this._el[2] = 0; 312 | this._el[3] = 0; 313 | 314 | this._el[4] = 0; 315 | this._el[5] = (near * 2) / b; 316 | this._el[6] = 0; 317 | this._el[7] = 0; 318 | 319 | this._el[8] = 0; 320 | this._el[9] = 0; 321 | this._el[10] = -(far + near) / c; 322 | this._el[11] = -1; 323 | 324 | this._el[12] = 0; 325 | this._el[13] = 0; 326 | this._el[14] = -(far * near * 2) / c; 327 | this._el[15] = 0; 328 | 329 | return this; 330 | } 331 | 332 | /** 333 | * 行列を転置する 334 | */ 335 | public transpose() { 336 | const a = this._el[0], 337 | b = this._el[1], 338 | c = this._el[2], 339 | d = this._el[3], 340 | e = this._el[4], 341 | f = this._el[5], 342 | g = this._el[6], 343 | h = this._el[7], 344 | i = this._el[8], 345 | j = this._el[9], 346 | k = this._el[10], 347 | l = this._el[11], 348 | m = this._el[12], 349 | n = this._el[13], 350 | o = this._el[14], 351 | p = this._el[15]; 352 | 353 | this._el[0] = a; 354 | this._el[1] = e; 355 | this._el[2] = i; 356 | this._el[3] = m; 357 | 358 | this._el[4] = b; 359 | this._el[5] = f; 360 | this._el[6] = j; 361 | this._el[7] = n; 362 | 363 | this._el[8] = c; 364 | this._el[9] = g; 365 | this._el[10] = k; 366 | this._el[11] = o; 367 | 368 | this._el[12] = d; 369 | this._el[13] = h; 370 | this._el[14] = l; 371 | this._el[15] = p; 372 | 373 | return this; 374 | } 375 | 376 | /** 377 | * 逆行列を生成する 378 | */ 379 | public inverse() { 380 | const a = this._el[0], 381 | b = this._el[1], 382 | c = this._el[2], 383 | d = this._el[3], 384 | e = this._el[4], 385 | f = this._el[5], 386 | g = this._el[6], 387 | h = this._el[7], 388 | i = this._el[8], 389 | j = this._el[9], 390 | k = this._el[10], 391 | l = this._el[11], 392 | m = this._el[12], 393 | n = this._el[13], 394 | o = this._el[14], 395 | p = this._el[15]; 396 | 397 | const q = a * f - b * e, 398 | r = a * g - c * e, 399 | s = a * h - d * e, 400 | t = b * g - c * f, 401 | u = b * h - d * f, 402 | v = c * h - d * g, 403 | w = i * n - j * m, 404 | x = i * o - k * m, 405 | y = i * p - l * m, 406 | z = j * o - k * n, 407 | A = j * p - l * n, 408 | B = k * p - l * o, 409 | ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w); 410 | 411 | this._el[0] = (f * B - g * A + h * z) * ivd; 412 | this._el[1] = (-b * B + c * A - d * z) * ivd; 413 | this._el[2] = (n * v - o * u + p * t) * ivd; 414 | this._el[3] = (-j * v + k * u - l * t) * ivd; 415 | 416 | this._el[4] = (-e * B + g * y - h * x) * ivd; 417 | this._el[5] = (a * B - c * y + d * x) * ivd; 418 | this._el[6] = (-m * v + o * s - p * r) * ivd; 419 | this._el[7] = (i * v - k * s + l * r) * ivd; 420 | 421 | this._el[8] = (e * A - f * y + h * w) * ivd; 422 | this._el[9] = (-a * A + b * y - d * w) * ivd; 423 | this._el[10] = (m * u - n * s + p * q) * ivd; 424 | this._el[11] = (-i * u + j * s - l * q) * ivd; 425 | 426 | this._el[12] = (-e * z + f * x - g * w) * ivd; 427 | this._el[13] = (a * z - b * x + c * w) * ivd; 428 | this._el[14] = (-m * t + n * r - o * q) * ivd; 429 | this._el[15] = (i * t - j * r + k * q) * ivd; 430 | 431 | return this; 432 | } 433 | 434 | /** 435 | * 複製する 436 | */ 437 | public clone() { 438 | const newMat = new Matrix4(); 439 | const a = this._el[0], 440 | b = this._el[1], 441 | c = this._el[2], 442 | d = this._el[3], 443 | e = this._el[4], 444 | f = this._el[5], 445 | g = this._el[6], 446 | h = this._el[7], 447 | i = this._el[8], 448 | j = this._el[9], 449 | k = this._el[10], 450 | l = this._el[11], 451 | m = this._el[12], 452 | n = this._el[13], 453 | o = this._el[14], 454 | p = this._el[15]; 455 | 456 | newMat.el[0] = a; 457 | newMat.el[1] = b; 458 | newMat.el[2] = c; 459 | newMat.el[3] = d; 460 | 461 | newMat.el[4] = e; 462 | newMat.el[5] = f; 463 | newMat.el[6] = g; 464 | newMat.el[7] = h; 465 | 466 | newMat.el[8] = i; 467 | newMat.el[9] = j; 468 | newMat.el[10] = k; 469 | newMat.el[11] = l; 470 | 471 | newMat.el[12] = m; 472 | newMat.el[13] = n; 473 | newMat.el[14] = o; 474 | newMat.el[15] = p; 475 | 476 | return newMat; 477 | } 478 | 479 | /** 480 | * 渡されたMatrix4の値を自分へコピーする 481 | */ 482 | public copy(mat: Matrix4) { 483 | this._el[0] = mat.el[0]; 484 | this._el[1] = mat.el[1]; 485 | this._el[2] = mat.el[2]; 486 | this._el[3] = mat.el[3]; 487 | 488 | this._el[4] = mat.el[4]; 489 | this._el[5] = mat.el[5]; 490 | this._el[6] = mat.el[6]; 491 | this._el[7] = mat.el[7]; 492 | 493 | this._el[8] = mat.el[8]; 494 | this._el[9] = mat.el[9]; 495 | this._el[10] = mat.el[10]; 496 | this._el[11] = mat.el[11]; 497 | 498 | this._el[12] = mat.el[12]; 499 | this._el[13] = mat.el[13]; 500 | this._el[14] = mat.el[14]; 501 | this._el[15] = mat.el[15]; 502 | 503 | return this; 504 | } 505 | 506 | public compose(position: Vector3, quaternion: Quaternion, scale: Vector3) { 507 | const x = quaternion.x, 508 | y = quaternion.y, 509 | z = quaternion.z, 510 | w = quaternion.w; 511 | const x2 = x + x, 512 | y2 = y + y, 513 | z2 = z + z; 514 | const xx = x * x2, 515 | xy = x * y2, 516 | xz = x * z2; 517 | const yy = y * y2, 518 | yz = y * z2, 519 | zz = z * z2; 520 | const wx = w * x2, 521 | wy = w * y2, 522 | wz = w * z2; 523 | 524 | const sx = scale.x, 525 | sy = scale.y, 526 | sz = scale.z; 527 | 528 | this._el[0] = (1 - (yy + zz)) * sx; 529 | this._el[1] = (xy + wz) * sx; 530 | this._el[2] = (xz - wy) * sx; 531 | this._el[3] = 0; 532 | 533 | this._el[4] = (xy - wz) * sy; 534 | this._el[5] = (1 - (xx + zz)) * sy; 535 | this._el[6] = (yz + wx) * sy; 536 | this._el[7] = 0; 537 | 538 | this._el[8] = (xz + wy) * sz; 539 | this._el[9] = (yz - wx) * sz; 540 | this._el[10] = (1 - (xx + yy)) * sz; 541 | this._el[11] = 0; 542 | 543 | this._el[12] = position.x; 544 | this._el[13] = position.y; 545 | this._el[14] = position.z; 546 | this._el[15] = 1; 547 | 548 | return this; 549 | } 550 | 551 | public getInverse(mat: Matrix4) { 552 | const a = mat.el[0], 553 | b = mat.el[1], 554 | c = mat.el[2], 555 | d = mat.el[3], 556 | e = mat.el[4], 557 | f = mat.el[5], 558 | g = mat.el[6], 559 | h = mat.el[7], 560 | i = mat.el[8], 561 | j = mat.el[9], 562 | k = mat.el[10], 563 | l = mat.el[11], 564 | m = mat.el[12], 565 | n = mat.el[13], 566 | o = mat.el[14], 567 | p = mat.el[15], 568 | q = a * f - b * e, 569 | r = a * g - c * e, 570 | s = a * h - d * e, 571 | t = b * g - c * f, 572 | u = b * h - d * f, 573 | v = c * h - d * g, 574 | w = i * n - j * m, 575 | x = i * o - k * m, 576 | y = i * p - l * m, 577 | z = j * o - k * n, 578 | A = j * p - l * n, 579 | B = k * p - l * o, 580 | ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w); 581 | this._el[0] = (f * B - g * A + h * z) * ivd; 582 | this._el[1] = (-b * B + c * A - d * z) * ivd; 583 | this._el[2] = (n * v - o * u + p * t) * ivd; 584 | this._el[3] = (-j * v + k * u - l * t) * ivd; 585 | this._el[4] = (-e * B + g * y - h * x) * ivd; 586 | this._el[5] = (a * B - c * y + d * x) * ivd; 587 | this._el[6] = (-m * v + o * s - p * r) * ivd; 588 | this._el[7] = (i * v - k * s + l * r) * ivd; 589 | this._el[8] = (e * A - f * y + h * w) * ivd; 590 | this._el[9] = (-a * A + b * y - d * w) * ivd; 591 | this._el[10] = (m * u - n * s + p * q) * ivd; 592 | this._el[11] = (-i * u + j * s - l * q) * ivd; 593 | this._el[12] = (-e * z + f * x - g * w) * ivd; 594 | this._el[13] = (a * z - b * x + c * w) * ivd; 595 | this._el[14] = (-m * t + n * r - o * q) * ivd; 596 | this._el[15] = (i * t - j * r + k * q) * ivd; 597 | 598 | return this; 599 | } 600 | } 601 | 602 | export default Matrix4; 603 | -------------------------------------------------------------------------------- /src/Mesh.ts: -------------------------------------------------------------------------------- 1 | import Object3D from './Object3D'; 2 | import Geometry from './Geometry'; 3 | import Material from './Material'; 4 | 5 | /** 6 | * Mesh 7 | */ 8 | class Mesh extends Object3D { 9 | private _geometry: Geometry; 10 | get geometry() { 11 | return this._geometry; 12 | } 13 | 14 | private _material: Material; 15 | get material() { 16 | return this._material; 17 | } 18 | 19 | constructor(geometry: Geometry, material: Material) { 20 | super(); 21 | 22 | this._geometry = geometry; 23 | this._material = material; 24 | } 25 | } 26 | 27 | export default Mesh; 28 | -------------------------------------------------------------------------------- /src/Object3D.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter from 'eventemitter3'; 2 | import { getUniqueStr } from './utils'; 3 | import Matrix4 from './Matrix4'; 4 | import Vector3 from './Vector3'; 5 | import Quaternion from './Quaternion'; 6 | 7 | /** 8 | * Object3D 9 | */ 10 | class Object3D extends EventEmitter { 11 | get id() { 12 | return this._id; 13 | } 14 | get position() { 15 | return this._position; 16 | } 17 | get up() { 18 | return this._up; 19 | } 20 | get scale() { 21 | return this._scale; 22 | } 23 | get rotation() { 24 | return this._rotation; 25 | } 26 | get quaternion() { 27 | return this._quaternion; 28 | } 29 | get parent(): Object3D | null { 30 | return this._parent; 31 | } 32 | set parent(obj: Object3D | null) { 33 | this._parent = obj; 34 | } 35 | get children() { 36 | return this._children; 37 | } 38 | get matrix() { 39 | return this._matrix; 40 | } 41 | get matrixWorld() { 42 | return this._matrixWorld; 43 | } 44 | get modelViewMatrix() { 45 | return this._modelViewMatrix; 46 | } 47 | private _id: string = getUniqueStr(); 48 | 49 | private _position: Vector3 = new Vector3(); 50 | 51 | private _up: Vector3 = new Vector3(0, 1, 0); 52 | 53 | private _scale: Vector3 = new Vector3(1, 1, 1); 54 | 55 | private _rotation: Vector3 = new Vector3(); 56 | 57 | private _quaternion: Quaternion = new Quaternion(); 58 | 59 | private _parent: Object3D | null = null; 60 | 61 | private _children: Object3D[] = []; 62 | 63 | private _matrix: Matrix4 = new Matrix4(); 64 | 65 | private _matrixWorld: Matrix4 = new Matrix4(); 66 | 67 | private _modelViewMatrix: Matrix4 = new Matrix4(); 68 | 69 | private _matrixWorldNeedsUpdate: boolean = false; 70 | 71 | constructor() { 72 | super(); 73 | 74 | this.rotation.on('change', this._onChangeRotation); 75 | } 76 | 77 | /** 78 | * 要素を追加する 79 | */ 80 | public add(obj: Object3D) { 81 | this._children.push(obj); 82 | obj.parent = this; 83 | } 84 | 85 | /** 86 | * ローカル変換行列を更新する 87 | */ 88 | public updateMatrix() { 89 | this._matrix.compose( 90 | this._position, 91 | this._quaternion, 92 | this._scale 93 | ); 94 | this._matrixWorldNeedsUpdate = true; 95 | } 96 | 97 | /** 98 | * ワールド座標を更新する 99 | */ 100 | public updateMatrixWorld() { 101 | this.updateMatrix(); 102 | 103 | if (this._matrixWorldNeedsUpdate) { 104 | if (this._parent) { 105 | this._matrixWorld.multiplyMatrices( 106 | this._parent.matrixWorld, 107 | this._matrix 108 | ); 109 | } else { 110 | this._matrixWorld.copy(this.matrix); 111 | } 112 | 113 | this._matrixWorldNeedsUpdate = false; 114 | } 115 | 116 | // update children 117 | const children = this._children; 118 | for (let i = 0, l = children.length; i < l; i++) { 119 | children[i].updateMatrixWorld(); 120 | } 121 | } 122 | 123 | private _onChangeRotation = () => { 124 | this._quaternion.setFromEuler(this._rotation); 125 | }; 126 | } 127 | 128 | export default Object3D; 129 | -------------------------------------------------------------------------------- /src/Points.ts: -------------------------------------------------------------------------------- 1 | import Object3D from './Object3D'; 2 | import Geometry from './Geometry'; 3 | import Material from './Material'; 4 | 5 | /** 6 | * Points 7 | */ 8 | class Points extends Object3D { 9 | private _geometry: Geometry; 10 | get geometry() { 11 | return this._geometry; 12 | } 13 | 14 | private _material: Material; 15 | get material() { 16 | return this._material; 17 | } 18 | 19 | constructor(geometry: Geometry, material: Material) { 20 | super(); 21 | 22 | this._geometry = geometry; 23 | this._material = material; 24 | } 25 | } 26 | 27 | export default Points; 28 | -------------------------------------------------------------------------------- /src/Quaternion.ts: -------------------------------------------------------------------------------- 1 | import Vector3 from './Vector3'; 2 | 3 | class Quaternion { 4 | private _x = 0; 5 | get x() { 6 | return this._x; 7 | } 8 | set x(value) { 9 | this._x = value; 10 | } 11 | 12 | private _y = 0; 13 | get y() { 14 | return this._y; 15 | } 16 | set y(value) { 17 | this._y = value; 18 | } 19 | 20 | private _z = 0; 21 | get z() { 22 | return this._z; 23 | } 24 | set z(value) { 25 | this._z = value; 26 | } 27 | 28 | private _w = 0; 29 | get w() { 30 | return this._w; 31 | } 32 | set w(value) { 33 | this._w = value; 34 | } 35 | 36 | constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 0) { 37 | this._x = x; 38 | this._y = y; 39 | this._z = z; 40 | this._w = w; 41 | } 42 | 43 | public setFromEuler(euler: Vector3) { 44 | const x = euler.x, 45 | y = euler.y, 46 | z = euler.z; 47 | 48 | const cos = Math.cos; 49 | const sin = Math.sin; 50 | 51 | const c1 = cos(x / 2); 52 | const c2 = cos(y / 2); 53 | const c3 = cos(z / 2); 54 | 55 | const s1 = sin(x / 2); 56 | const s2 = sin(y / 2); 57 | const s3 = sin(z / 2); 58 | 59 | this._x = s1 * c2 * c3 + c1 * s2 * s3; 60 | this._y = c1 * s2 * c3 - s1 * c2 * s3; 61 | this._z = c1 * c2 * s3 + s1 * s2 * c3; 62 | this._w = c1 * c2 * c3 - s1 * s2 * s3; 63 | 64 | return this; 65 | } 66 | } 67 | 68 | export default Quaternion; 69 | -------------------------------------------------------------------------------- /src/Renderer.ts: -------------------------------------------------------------------------------- 1 | import Matrix4 from './Matrix4'; 2 | import Scene from './Scene'; 3 | import Mesh from './Mesh'; 4 | import Points from './Points'; 5 | import Object3D from './Object3D'; 6 | import Camera from './Camera'; 7 | import { 8 | getContext, 9 | createProgram, 10 | createVbo, 11 | createTexture, 12 | enabledDepthTest, 13 | switchBlending, 14 | switchCulling, 15 | drawFace, 16 | drawPoints, 17 | clearColor 18 | } from './utils'; 19 | 20 | interface AttributesInfo { 21 | [name: string]: { 22 | vbo: WebGLBuffer; 23 | attrLoc: GLint; 24 | stride: number; 25 | }; 26 | } 27 | 28 | interface UniformsInfo { 29 | [name: string]: WebGLUniformLocation; 30 | } 31 | 32 | interface Texture { 33 | slot: number; 34 | image: HTMLImageElement; 35 | webglTexture: WebGLTexture; 36 | } 37 | 38 | type RenderableObject = Mesh | Points; 39 | interface RenderItem { 40 | obj: RenderableObject; 41 | program: WebGLProgram; 42 | attributes: AttributesInfo; 43 | uniforms: UniformsInfo; 44 | } 45 | 46 | class Renderer { 47 | set pixelRatio(value) { 48 | this._pixelRatio = value; 49 | } 50 | get pixelRatio() { 51 | return this._pixelRatio; 52 | } 53 | get domElement() { 54 | return this._domElement; 55 | } 56 | set clearColor(color: number[]) { 57 | this._clearColor = color; 58 | } 59 | private _gl: WebGLRenderingContext; 60 | private _renderList: RenderItem[] = []; 61 | private _pMatrix = new Matrix4(); 62 | private _textures: Texture[] = []; 63 | private _width: number = 400; 64 | private _height: number = 300; 65 | 66 | private _pixelRatio: number = 2; 67 | 68 | private _domElement: HTMLCanvasElement = document.createElement('canvas'); 69 | 70 | private _clearColor: number[] = [0.0, 0.0, 0.0, 1.0]; 71 | 72 | constructor(attributes: WebGLContextAttributes = {}) { 73 | this._gl = getContext(this._domElement, attributes); 74 | this.setSize(this._width, this._height); 75 | } 76 | 77 | public setSize(w: number, h: number) { 78 | const canvasW = w * this._pixelRatio; 79 | const canvasH = h * this._pixelRatio; 80 | 81 | this._width = w; 82 | this._height = h; 83 | 84 | this._domElement!.style.width = this._width + 'px'; 85 | this._domElement!.style.height = this._height + 'px'; 86 | 87 | this._domElement!.width = canvasW; 88 | this._domElement!.height = canvasH; 89 | this._gl.viewport(0, 0, canvasW, canvasH); 90 | this._pMatrix.perspective(90, canvasW / canvasH, 0.1, 100); 91 | } 92 | 93 | public render(scene: Scene, camera: Camera) { 94 | // canvasをクリア 95 | clearColor(this._gl, this._clearColor); 96 | 97 | // ワールド変換座標を更新 98 | scene.updateMatrixWorld(); 99 | camera.updateMatrixWorld(); 100 | 101 | if (scene.needsUpdate) { 102 | this._renderList = []; 103 | this._projectObject(scene); 104 | scene.needsUpdate = false; 105 | } 106 | 107 | // オブジェクトを描画する 108 | this._renderList.forEach(renderItem => { 109 | this._renderObj(renderItem, camera); 110 | }); 111 | 112 | // コンテキストの再描画 113 | this._gl.flush(); 114 | } 115 | 116 | /** 117 | * 描画に必要なデータの生成をする 118 | */ 119 | private _projectObject(obj: Object3D) { 120 | if (obj instanceof Mesh || obj instanceof Points) { 121 | // プログラムオブジェクトの生成とリンク 122 | const program = createProgram( 123 | this._gl, 124 | obj.material.vertexShader, 125 | obj.material.fragmentShader 126 | ); 127 | 128 | // アトリビュートを登録 129 | const attributes: AttributesInfo = {}; 130 | Object.keys(obj.geometry.attributes).forEach(name => { 131 | const attribute = obj.geometry.attributes[name]; 132 | const attributeInfo = { 133 | vbo: createVbo(this._gl, attribute.verticies), 134 | attrLoc: this._gl.getAttribLocation(program, name), 135 | stride: attribute.stride 136 | }; 137 | attributes[name] = attributeInfo; 138 | }); 139 | 140 | // ユニフォームを登録 141 | const uniforms: UniformsInfo = {}; 142 | Object.keys(obj.material.uniforms).forEach(name => { 143 | const originUniform = obj.material.uniforms[name]; 144 | uniforms[name] = this._gl.getUniformLocation(program, name)!; 145 | 146 | // uniformでtのタイプのときはテクスチャを登録する 147 | if (originUniform.type === 't') { 148 | const slot = this._gl.TEXTURE0; 149 | const image: HTMLImageElement = originUniform.value!; 150 | const webglTexture = createTexture(this._gl, image, slot); 151 | this._textures.push({ slot, image, webglTexture }); 152 | } 153 | }); 154 | 155 | const renderItem: RenderItem = { 156 | obj, 157 | program, 158 | attributes, 159 | uniforms 160 | }; 161 | 162 | this._renderList.push(renderItem); 163 | } 164 | 165 | obj.children.forEach(child => { 166 | this._projectObject(child); 167 | }); 168 | } 169 | 170 | private _renderObj(renderItem: RenderItem, camera: Camera) { 171 | const obj = renderItem.obj; 172 | const prg = renderItem.program; 173 | const attributes = renderItem.attributes; 174 | const uniforms = renderItem.uniforms; 175 | const geometry = obj.geometry; 176 | const material = obj.material; 177 | 178 | obj.modelViewMatrix.multiplyMatrices( 179 | camera.matrixWorldInverse, 180 | obj.matrixWorld 181 | ); 182 | 183 | Object.keys(attributes).forEach(name => { 184 | const attribute = attributes[name]; 185 | // アトリビュートを許可 186 | this._gl.bindBuffer(this._gl.ARRAY_BUFFER, attribute.vbo); 187 | this._gl.enableVertexAttribArray(attribute.attrLoc); 188 | this._gl.vertexAttribPointer( 189 | attribute.attrLoc, 190 | attribute.stride, 191 | this._gl.FLOAT, 192 | false, 193 | 0, 194 | 0 195 | ); 196 | // バッファを開放 197 | this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null); 198 | }); 199 | 200 | // 使用するプログラムを指定 201 | this._gl.useProgram(prg); 202 | 203 | // uniformの値を反映 204 | material.uniforms.mMatrix.value = obj.matrix; 205 | material.uniforms.vMatrix.value = camera.matrixWorldInverse; 206 | material.uniforms.pMatrix.value = this._pMatrix; 207 | material.uniforms.mvMatrix.value = obj.modelViewMatrix; 208 | Object.keys(uniforms).forEach(name => { 209 | const uniformLoc = uniforms[name]; 210 | const uniform = material.uniforms[name]; 211 | switch (uniform.type) { 212 | case 'v4': 213 | this._gl.uniformMatrix4fv(uniformLoc, false, uniform.value.el); 214 | break; 215 | case 'f': 216 | this._gl.uniform1f(uniformLoc, uniform.value); 217 | break; 218 | case 't': 219 | const texture = this._textures.find(t => { 220 | return t.image.src === uniform.value.src; 221 | }); 222 | if (texture) { 223 | this._gl.activeTexture(this._gl.TEXTURE0); 224 | this._gl.bindTexture(this._gl.TEXTURE_2D, texture.webglTexture); 225 | this._gl.uniform1i(uniformLoc, 0); 226 | } 227 | break; 228 | } 229 | }); 230 | 231 | // 深度テストを有効 232 | enabledDepthTest(this._gl); 233 | 234 | // ブレンディングを切り替え 235 | switchBlending(this._gl, material.transparent); 236 | 237 | // カリングを切り替える 238 | switchCulling(this._gl, material.side); 239 | 240 | if (obj instanceof Mesh) { 241 | // 面を描画 242 | drawFace(this._gl, geometry.index); 243 | } else if (obj instanceof Points) { 244 | // ポイントを描画 245 | drawPoints(this._gl, geometry.attributes.position.verticies); 246 | } 247 | } 248 | } 249 | 250 | export default Renderer; 251 | -------------------------------------------------------------------------------- /src/Scene.ts: -------------------------------------------------------------------------------- 1 | import Object3D from './Object3D'; 2 | 3 | class Scene extends Object3D { 4 | _needsUpdate = true; 5 | get needsUpdate() { 6 | return this._needsUpdate; 7 | } 8 | set needsUpdate(flag: boolean) { 9 | this._needsUpdate = flag; 10 | } 11 | 12 | constructor() { 13 | super(); 14 | } 15 | } 16 | 17 | export default Scene; 18 | -------------------------------------------------------------------------------- /src/Vector3.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter from 'eventemitter3'; 2 | 3 | class Vector3 extends EventEmitter { 4 | private _x = 0; 5 | get x() { 6 | return this._x; 7 | } 8 | set x(value) { 9 | this._x = value; 10 | this.emit('change'); 11 | } 12 | 13 | private _y = 0; 14 | get y() { 15 | return this._y; 16 | } 17 | set y(value) { 18 | this._y = value; 19 | this.emit('change'); 20 | } 21 | 22 | private _z = 0; 23 | get z() { 24 | return this._z; 25 | } 26 | set z(value) { 27 | this._z = value; 28 | this.emit('change'); 29 | } 30 | 31 | constructor(x: number = 0, y: number = 0, z: number = 0) { 32 | super(); 33 | 34 | this._x = x; 35 | this._y = y; 36 | this._z = z; 37 | } 38 | } 39 | 40 | export default Vector3; 41 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import Renderer from './Renderer'; 2 | import Matrix4 from './Matrix4'; 3 | import Object3D from './Object3D'; 4 | import Geometry from './Geometry'; 5 | import Material from './Material'; 6 | import Mesh from './Mesh'; 7 | import Points from './Points'; 8 | import Scene from './Scene'; 9 | import Vector3 from './Vector3'; 10 | import Quaternion from './Quaternion'; 11 | import Camera from './Camera'; 12 | 13 | export default { 14 | Renderer, 15 | Matrix4, 16 | Object3D, 17 | Geometry, 18 | Material, 19 | Mesh, 20 | Points, 21 | Scene, 22 | Vector3, 23 | Quaternion, 24 | Camera 25 | }; 26 | -------------------------------------------------------------------------------- /src/utils/__tests__/index.test.ts: -------------------------------------------------------------------------------- 1 | import { getContext } from '../index'; 2 | 3 | describe('getContext', () => { 4 | test('is not undefined', () => { 5 | const canvas = document.createElement('canvas'); 6 | expect(getContext(canvas)).not.toBeUndefined(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export enum Side { 2 | FRONT = 'SIDE_FRONT', 3 | BACK = 'SIDE_BACK', 4 | DOUBLE = 'SIDE_DOUBLE' 5 | } 6 | 7 | export const getContext = ( 8 | canvas: HTMLCanvasElement, 9 | attributes: WebGLContextAttributes = {} 10 | ): WebGLRenderingContext => { 11 | const gl: WebGLRenderingContext = 12 | canvas.getContext('webgl', attributes)! || 13 | canvas.getContext('experimental-webgl', attributes)!; 14 | 15 | return gl; 16 | }; 17 | 18 | export const createShader = ( 19 | gl: WebGLRenderingContext, 20 | shaderSource: string, 21 | shaderType: number 22 | ) => { 23 | // scriptタグのtype属性をチェック 24 | const shader = gl.createShader(shaderType)!; 25 | 26 | // 生成されたシェーダにソースを割り当てる 27 | gl.shaderSource(shader, shaderSource); 28 | 29 | // シェーダをコンパイルする 30 | gl.compileShader(shader); 31 | 32 | // シェーダが正しくコンパイルされたかチェック 33 | const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 34 | if (!success) { 35 | // コンパイル中に問題があった場合、エラーを取得する。 36 | throw new Error(`could not compile shader:${gl.getShaderInfoLog(shader)}`); 37 | } 38 | 39 | return shader; 40 | }; 41 | 42 | export const createProgram = ( 43 | gl: WebGLRenderingContext, 44 | vertexSource: string, 45 | fragmentSource: string 46 | ) => { 47 | const vertexShader = createShader(gl, vertexSource, gl.VERTEX_SHADER); 48 | const fragmentShader = createShader(gl, fragmentSource, gl.FRAGMENT_SHADER); 49 | 50 | // プログラムを生成する。 51 | const program = gl.createProgram()!; 52 | 53 | // シェーダーをアタッチする。 54 | gl.attachShader(program, vertexShader); 55 | gl.attachShader(program, fragmentShader); 56 | 57 | // プログラムをリンクする。 58 | gl.linkProgram(program); 59 | 60 | // リンクが成功したか確認する。 61 | const success = gl.getProgramParameter(program, gl.LINK_STATUS); 62 | if (success) { 63 | // 成功していたらプログラムオブジェクトを有効にする 64 | gl.useProgram(program); 65 | } else { 66 | // リンク中に問題があった場合、エラーを取得する。 67 | throw new Error(`program filed to link:${gl.getProgramInfoLog(program)}`); 68 | } 69 | 70 | return program; 71 | }; 72 | 73 | /** 74 | * VBOを生成する 75 | */ 76 | export const createVbo = ( 77 | gl: WebGLRenderingContext, 78 | verticies: number[] 79 | ): WebGLBuffer => { 80 | // バッファオブジェクトの生成 81 | const vbo: WebGLBuffer = gl.createBuffer()!; 82 | 83 | // バッファをバインドする 84 | gl.bindBuffer(gl.ARRAY_BUFFER, vbo); 85 | 86 | // バッファにデータをセット 87 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticies), gl.STATIC_DRAW); 88 | 89 | // バッファのバインドを無効化 90 | gl.bindBuffer(gl.ARRAY_BUFFER, null); 91 | 92 | return vbo; 93 | }; 94 | 95 | /** 96 | * IBOを生成する 97 | */ 98 | export const createIbo = ( 99 | gl: WebGLRenderingContext, 100 | index: number[] 101 | ): WebGLBuffer => { 102 | // バッファオブジェクトの生成 103 | const ibo = gl.createBuffer()!; 104 | 105 | // バッファをバインドする 106 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); 107 | 108 | // バッファにデータをセット 109 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(index), gl.STATIC_DRAW); 110 | 111 | // バッファのバインドを無効化 112 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 113 | 114 | return ibo; 115 | }; 116 | 117 | /** 118 | * テクスチャを作成する 119 | */ 120 | export const createTexture = ( 121 | gl: WebGLRenderingContext, 122 | image: HTMLImageElement, 123 | textureNumber: number 124 | ): WebGLTexture => { 125 | // テクスチャオブジェクトの生成 126 | const tex = gl.createTexture()!; 127 | // 有効にするテクスチャユニットを指定 128 | gl.activeTexture(textureNumber); 129 | // テクスチャをバインドする 130 | gl.bindTexture(gl.TEXTURE_2D, tex); 131 | // テクスチャへイメージを適用 132 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 133 | // ミップマップを生成 134 | gl.generateMipmap(gl.TEXTURE_2D); 135 | // テクスチャのバインドを無効化 136 | gl.bindTexture(gl.TEXTURE_2D, null); 137 | 138 | return tex; 139 | }; 140 | 141 | /** 142 | * 深度テストを有効にする 143 | */ 144 | export const enabledDepthTest = (gl: WebGLRenderingContext) => { 145 | gl.enable(gl.DEPTH_TEST); 146 | gl.depthFunc(gl.LEQUAL); 147 | }; 148 | 149 | /** 150 | * カリングの切り替え 151 | */ 152 | export const switchCulling = (gl: WebGLRenderingContext, side: Side) => { 153 | switch (side) { 154 | case Side.DOUBLE: 155 | gl.disable(gl.CULL_FACE); 156 | break; 157 | case Side.BACK: 158 | gl.enable(gl.CULL_FACE); 159 | gl.frontFace(gl.CW); 160 | break; 161 | case Side.FRONT: 162 | default: 163 | gl.enable(gl.CULL_FACE); 164 | gl.frontFace(gl.CCW); 165 | break; 166 | } 167 | }; 168 | 169 | /** 170 | * ブレンディングの切り替え 171 | */ 172 | export const switchBlending = ( 173 | gl: WebGLRenderingContext, 174 | transparent: boolean 175 | ) => { 176 | if (transparent) { 177 | // ブレンディングを有効 178 | gl.enable(gl.BLEND); 179 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 180 | } else { 181 | gl.disable(gl.BLEND); 182 | } 183 | }; 184 | 185 | /** 186 | * 面を描画 187 | */ 188 | export const drawFace = (gl: WebGLRenderingContext, index: number[]) => { 189 | const ibo = createIbo(gl, index); 190 | // IBOをバインドして登録する 191 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); 192 | // モデルの描画 193 | gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0); 194 | }; 195 | 196 | /** 197 | * ポイントを描画 198 | */ 199 | export const drawPoints = (gl: WebGLRenderingContext, verticies: number[]) => { 200 | gl.drawArrays(gl.POINTS, 0, verticies.length / 3); 201 | }; 202 | 203 | /** 204 | * 描画をクリア 205 | */ 206 | export const clearColor = ( 207 | gl: WebGLRenderingContext, 208 | color = [0.0, 0.0, 0.0, 1.0], 209 | depth = 1.0 210 | ) => { 211 | // canvasを単色でクリア(初期化) 212 | gl.clearColor(color[0], color[1], color[2], color[3]); 213 | // canvasを初期化する際の深度を設定する 214 | gl.clearDepth(depth); 215 | // canvasを初期化 216 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 217 | }; 218 | 219 | /** 220 | * ユニークな文字列を作成 221 | */ 222 | export const getUniqueStr = (strong: number = 1000): string => { 223 | return ( 224 | new Date().getTime().toString(16) + 225 | Math.floor(strong * Math.random()).toString(16) 226 | ); 227 | }; 228 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "lib": ["dom", "es2015"], 6 | "allowJs": true, 7 | "strict": true, 8 | "allowSyntheticDefaultImports": true, 9 | "experimentalDecorators": true, 10 | "noImplicitReturns": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "removeComments": true, 15 | "moduleResolution": "node", 16 | "esModuleInterop": true, 17 | "noEmit": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["tslint-plugin-prettier"], 3 | "extends": [ 4 | "tslint:recommended", 5 | "tslint-config-prettier" 6 | ], 7 | "rules": { 8 | "prettier": [ 9 | true, 10 | { 11 | "singleQuote": true 12 | } 13 | ], 14 | "import-name": false, 15 | "no-use-before-declare": false, 16 | "no-bitwise": false, 17 | "jsx-no-multiline-js": false, 18 | "object-literal-sort-keys": false, 19 | "ordered-imports": false, 20 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"], 21 | "one-variable-per-declaration": false, 22 | "interface-name" : [true, "never-prefix"] 23 | }, 24 | "linterOptions": { 25 | "typeCheck": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); 4 | const projectRootPath = path.resolve(__dirname, './'); 5 | const assetsPath = path.resolve(projectRootPath, './dist'); 6 | 7 | module.exports = { 8 | entry: `${__dirname}/src/index.ts`, 9 | output: { 10 | path: assetsPath, 11 | filename: 'shree.js', 12 | library: 'SHREE', 13 | libraryTarget: 'umd', 14 | libraryExport: 'default', 15 | }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.ts$/, 20 | use: { 21 | loader: 'ts-loader', 22 | options: { 23 | transpileOnly: true 24 | } 25 | } 26 | } 27 | ] 28 | }, 29 | resolve: { 30 | extensions: [ 31 | '.ts' 32 | ] 33 | }, 34 | plugins: [ 35 | new ForkTsCheckerWebpackPlugin() 36 | ] 37 | }; 38 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common, { 5 | mode: 'development', 6 | devtool: 'devtool.source-map', 7 | }); 8 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require('webpack-merge'); 3 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 4 | const common = require('./webpack.common.js'); 5 | 6 | module.exports = merge(common, { 7 | mode: 'production', 8 | plugins: [ 9 | new webpack.DefinePlugin({ 10 | 'process.env': { 11 | NODE_ENV: JSON.stringify('production'), 12 | }, 13 | }), 14 | ], 15 | optimization: { 16 | minimizer: [new UglifyJSPlugin()], 17 | }, 18 | }); 19 | --------------------------------------------------------------------------------