├── .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 | [](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 |

56 |

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 |

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 |
--------------------------------------------------------------------------------