diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index b7c7d4b..719a2d3 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,6 +1,6 @@
name: CI
-on: [push]
+on: [push, pull_request]
jobs:
test:
@@ -9,8 +9,6 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: npm build & test
- run: |
- npm install
- npm run build
- npm test
+ - run: npm install
+ - run: npm run build
+ - run: npm test
diff --git a/.github/workflows/deploy-ghpages.yaml b/.github/workflows/deploy-ghpages.yaml
new file mode 100644
index 0000000..983fd12
--- /dev/null
+++ b/.github/workflows/deploy-ghpages.yaml
@@ -0,0 +1,31 @@
+name: Deploy to GitHub Pages
+on:
+ push:
+ branches:
+ - master
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - run: npm install
+ - run: npm run build
+ - run: npm test
+ - name: Prepare files
+ run: |
+ cp -r examples public
+ cp -r bundles public/js
+ build_commit="${{ github.sha }}"
+ build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
+ sed -Ez \
+ -e 's#\.\./bundles/skinview3d\.bundle\.js#js/skinview3d.bundle.js#g' \
+ -e 's#\{\{build_commit\}\}#'$build_commit'#g' \
+ -e 's#\{\{build_time\}\}#'$build_time'#g' \
+ -e 's##\1#g' \
+ -i public/*.html
+ - uses: crazy-max/ghaction-github-pages@v2
+ with:
+ target_branch: gh-pages
+ build_dir: public
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index ffea957..683c975 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,4 @@ libs/
_ignore/
.DS_Store
.rpt2_cache
+public/
diff --git a/README.md b/README.md
index 832f5b6..09176db 100644
--- a/README.md
+++ b/README.md
@@ -16,11 +16,12 @@ Three.js powered Minecraft skin viewer.
* Automatic model detection (Slim / Default)
# Usage
-[Examples of using the viewer](https://bs-community.github.io/skinview3d/)
+[Example of using skinview3d](https://bs-community.github.io/skinview3d/)
```html
-
+
```
+## Anti-aliasing
+skinview3d supports FXAA (fast approximate anti-aliasing).
+To enable it, you need to replace `SkinViewer` with `FXAASkinViewer`.
+
+It's recommended to use an opaque background when FXAA is enabled,
+as transparent background may look buggy.
+
+```javascript
+let skinViewer = new skinview3d.FXAASkinViewer({
+ // we do not use transparent background, so disable alpha to improve performance
+ alpha: false,
+ ...
+});
+// set the background color
+skinViewer.renderer.setClearColor(0x5a76f3);
+```
+
# Build
`npm run build`
diff --git a/examples/img/1_8_texturemap_redux.png b/examples/img/1_8_texturemap_redux.png
new file mode 100644
index 0000000..a206b32
Binary files /dev/null and b/examples/img/1_8_texturemap_redux.png differ
diff --git a/examples/img/hacksore.png b/examples/img/hacksore.png
new file mode 100644
index 0000000..72f254f
Binary files /dev/null and b/examples/img/hacksore.png differ
diff --git a/examples/img/haka.png b/examples/img/haka.png
new file mode 100644
index 0000000..cfcbfc5
Binary files /dev/null and b/examples/img/haka.png differ
diff --git a/examples/img/hatsune_miku.png b/examples/img/hatsune_miku.png
new file mode 100644
index 0000000..d434946
Binary files /dev/null and b/examples/img/hatsune_miku.png differ
diff --git a/examples/img/hd_cape.png b/examples/img/hd_cape.png
new file mode 100644
index 0000000..81b20d3
Binary files /dev/null and b/examples/img/hd_cape.png differ
diff --git a/examples/img/ironman_hd.png b/examples/img/ironman_hd.png
new file mode 100644
index 0000000..bae9374
Binary files /dev/null and b/examples/img/ironman_hd.png differ
diff --git a/examples/img/legacy_cape.png b/examples/img/legacy_cape.png
new file mode 100644
index 0000000..01a8f65
Binary files /dev/null and b/examples/img/legacy_cape.png differ
diff --git a/examples/img/mojang_cape.png b/examples/img/mojang_cape.png
new file mode 100644
index 0000000..deac5c5
Binary files /dev/null and b/examples/img/mojang_cape.png differ
diff --git a/examples/img/sethbling.png b/examples/img/sethbling.png
new file mode 100644
index 0000000..db47a84
Binary files /dev/null and b/examples/img/sethbling.png differ
diff --git a/examples/index.html b/examples/index.html
old mode 100755
new mode 100644
index 0556c68..8256ceb
--- a/examples/index.html
+++ b/examples/index.html
@@ -1,75 +1,441 @@
-
-
-
-
-
- skinview3d
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ skinview3d
+
+
+
+
+
+
+
+
+
+
+
+
+
Canvas Size
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/offscreen-render.html b/examples/offscreen-render.html
new file mode 100644
index 0000000..249aaad
--- /dev/null
+++ b/examples/offscreen-render.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+ skinview3d / offscreen-render
+
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 0f3337c..e1e6861 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,31 +1,31 @@
{
"name": "skinview3d",
- "version": "2.0.0-alpha.5",
+ "version": "2.0.0-alpha.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/code-frame": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
- "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.8.3"
+ "@babel/highlight": "^7.10.4"
}
},
"@babel/helper-validator-identifier": {
- "version": "7.9.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
- "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
"dev": true
},
"@babel/highlight": {
- "version": "7.9.0",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
- "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.9.0",
+ "@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
@@ -40,15 +40,20 @@
}
},
"@rollup/plugin-node-resolve": {
+<<<<<<< HEAD
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz",
"integrity": "sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==",
+=======
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz",
+ "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==",
+>>>>>>> upstream/master
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
"@types/resolve": "1.17.1",
"builtin-modules": "^3.1.0",
- "deep-freeze": "^0.0.1",
"deepmerge": "^4.2.2",
"is-module": "^1.0.0",
"resolve": "^1.17.0"
@@ -117,9 +122,15 @@
"dev": true
},
"@types/node": {
+<<<<<<< HEAD
"version": "14.0.22",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.22.tgz",
"integrity": "sha512-emeGcJvdiZ4Z3ohbmw93E/64jRzUHAItSHt8nF7M4TGgQTiWqFVGB8KNpLGFmUHmHLvjvBgFwVlqNcq+VuGv9g==",
+=======
+ "version": "14.6.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.0.tgz",
+ "integrity": "sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA==",
+>>>>>>> upstream/master
"dev": true
},
"@types/resolve": {
@@ -132,12 +143,21 @@
}
},
"@typescript-eslint/eslint-plugin": {
+<<<<<<< HEAD
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.6.0.tgz",
"integrity": "sha512-ubHlHVt1lsPQB/CZdEov9XuOFhNG9YRC//kuiS1cMQI6Bs1SsqKrEmZnpgRwthGR09/kEDtr9MywlqXyyYd8GA==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "3.6.0",
+=======
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.9.1.tgz",
+ "integrity": "sha512-XIr+Mfv7i4paEdBf0JFdIl9/tVxyj+rlilWIfZ97Be0lZ7hPvUbS5iHt9Glc8kRI53dsr0PcAEudbf8rO2wGgg==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/experimental-utils": "3.9.1",
+>>>>>>> upstream/master
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
"regexpp": "^3.0.0",
@@ -146,6 +166,7 @@
}
},
"@typescript-eslint/experimental-utils": {
+<<<<<<< HEAD
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.6.0.tgz",
"integrity": "sha512-4Vdf2hvYMUnTdkCNZu+yYlFtL2v+N2R7JOynIOkFbPjf9o9wQvRwRkzUdWlFd2YiiUwJLbuuLnl5civNg5ykOQ==",
@@ -154,11 +175,22 @@
"@types/json-schema": "^7.0.3",
"@typescript-eslint/types": "3.6.0",
"@typescript-eslint/typescript-estree": "3.6.0",
+=======
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.9.1.tgz",
+ "integrity": "sha512-lkiZ8iBBaYoyEKhCkkw4SAeatXyBq9Ece5bZXdLe1LWBUwTszGbmbiqmQbwWA8cSYDnjWXp9eDbXpf9Sn0hLAg==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/types": "3.9.1",
+ "@typescript-eslint/typescript-estree": "3.9.1",
+>>>>>>> upstream/master
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/parser": {
+<<<<<<< HEAD
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.6.0.tgz",
"integrity": "sha512-taghDxuLhbDAD1U5Fk8vF+MnR0yiFE9Z3v2/bYScFb0N1I9SK8eKHkdJl1DAD48OGFDMFTeOTX0z7g0W6SYUXw==",
@@ -168,10 +200,22 @@
"@typescript-eslint/experimental-utils": "3.6.0",
"@typescript-eslint/types": "3.6.0",
"@typescript-eslint/typescript-estree": "3.6.0",
+=======
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.9.1.tgz",
+ "integrity": "sha512-y5QvPFUn4Vl4qM40lI+pNWhTcOWtpZAJ8pOEQ21fTTW4xTJkRplMjMRje7LYTXqVKKX9GJhcyweMz2+W1J5bMg==",
+ "dev": true,
+ "requires": {
+ "@types/eslint-visitor-keys": "^1.0.0",
+ "@typescript-eslint/experimental-utils": "3.9.1",
+ "@typescript-eslint/types": "3.9.1",
+ "@typescript-eslint/typescript-estree": "3.9.1",
+>>>>>>> upstream/master
"eslint-visitor-keys": "^1.1.0"
}
},
"@typescript-eslint/types": {
+<<<<<<< HEAD
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.6.0.tgz",
"integrity": "sha512-JwVj74ohUSt0ZPG+LZ7hb95fW8DFOqBuR6gE7qzq55KDI3BepqsCtHfBIoa0+Xi1AI7fq5nCu2VQL8z4eYftqg==",
@@ -185,6 +229,21 @@
"requires": {
"@typescript-eslint/types": "3.6.0",
"@typescript-eslint/visitor-keys": "3.6.0",
+=======
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.9.1.tgz",
+ "integrity": "sha512-15JcTlNQE1BsYy5NBhctnEhEoctjXOjOK+Q+rk8ugC+WXU9rAcS2BYhoh6X4rOaXJEpIYDl+p7ix+A5U0BqPTw==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.9.1.tgz",
+ "integrity": "sha512-IqM0gfGxOmIKPhiHW/iyAEXwSVqMmR2wJ9uXHNdFpqVvPaQ3dWg302vW127sBpAiqM9SfHhyS40NKLsoMpN2KA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "3.9.1",
+ "@typescript-eslint/visitor-keys": "3.9.1",
+>>>>>>> upstream/master
"debug": "^4.1.1",
"glob": "^7.1.6",
"is-glob": "^4.0.1",
@@ -194,21 +253,50 @@
}
},
"@typescript-eslint/visitor-keys": {
+<<<<<<< HEAD
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.6.0.tgz",
"integrity": "sha512-p1izllL2Ubwunite0ITjubuMQRBGgjdVYwyG7lXPX8GbrA6qF0uwSRz9MnXZaHMxID4948gX0Ez8v9tUDi/KfQ==",
+=======
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.9.1.tgz",
+ "integrity": "sha512-zxdtUjeoSh+prCpogswMwVUJfEFmCOjdzK9rpNjNBfm6EyPt99x3RrJoBOGZO23FCt0WPKUCOL5mb/9D5LjdwQ==",
+>>>>>>> upstream/master
"dev": true,
"requires": {
"eslint-visitor-keys": "^1.1.0"
}
},
- "@yushijinhun/three-minifier-rollup": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/@yushijinhun/three-minifier-rollup/-/three-minifier-rollup-0.1.7.tgz",
- "integrity": "sha512-GzlFkEzUqyI8X23guT7Y8R3KaCzCXdUNpWfSPiq7m/f3xUNhhclFJORWqurZdnSEnxWCiCMgNm/9GsLMd/N2Qw==",
+<<<<<<< HEAD
+=======
+ "@yushijinhun/three-minifier-common": {
+ "version": "0.2.0-alpha.2",
+ "resolved": "https://registry.npmjs.org/@yushijinhun/three-minifier-common/-/three-minifier-common-0.2.0-alpha.2.tgz",
+ "integrity": "sha512-Y2NlRcyvEQmY5FlELV/Az7UElddTqKwZxA77OB0of5sj610pa2pM+IlwC20qgEXMaqfdULaENjYGi5EHPK0RSQ==",
"dev": true,
"requires": {
- "@rollup/plugin-node-resolve": "^8.0.0",
+ "acorn": "^8.0.1",
+ "acorn-walk": "^8.0.0",
+ "glsl-tokenizer": "^2.1.5"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.1.tgz",
+ "integrity": "sha512-dmKn4pqZ29iQl2Pvze1zTrps2luvls2PBY//neO2WJ0s10B3AxJXshN+Ph7B4GrhfGhHXrl4dnUwyNNXQcnWGQ==",
+ "dev": true
+ }
+ }
+ },
+>>>>>>> upstream/master
+ "@yushijinhun/three-minifier-rollup": {
+ "version": "0.2.0-alpha.2",
+ "resolved": "https://registry.npmjs.org/@yushijinhun/three-minifier-rollup/-/three-minifier-rollup-0.2.0-alpha.2.tgz",
+ "integrity": "sha512-jB9efJwsX9M4QGx4/rA760H9G44tnGq6gIG/ZlP8PWKIBdw48JmRlk20LP1mCT0SH6CKGZcdE0DwR3At+ssGXg==",
+ "dev": true,
+ "requires": {
+ "@rollup/plugin-node-resolve": "^9.0.0",
+ "@yushijinhun/three-minifier-common": "^0.2.0-alpha.2",
"magic-string": "^0.25.7"
}
},
@@ -233,9 +321,9 @@
}
},
"acorn": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
- "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==",
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
+ "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
"dev": true
},
"acorn-jsx": {
@@ -244,19 +332,31 @@
"integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
"dev": true
},
+ "acorn-walk": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.0.tgz",
+ "integrity": "sha512-oZRad/3SMOI/pxbbmqyurIx7jHw1wZDcR9G44L8pUVFEomX/0dH89SrM1KaDXuv1NpzAXz6Op/Xu/Qd5XXzdEA==",
+ "dev": true
+ },
"agent-base": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz",
- "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz",
+ "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==",
"dev": true,
"requires": {
"debug": "4"
}
},
"ajv": {
+<<<<<<< HEAD
"version": "6.12.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
+=======
+ "version": "6.12.4",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
+ "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
+>>>>>>> upstream/master
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@@ -643,12 +743,6 @@
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
- "deep-freeze": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz",
- "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=",
- "dev": true
- },
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -776,9 +870,15 @@
"dev": true
},
"eslint": {
+<<<<<<< HEAD
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.4.0.tgz",
"integrity": "sha512-gU+lxhlPHu45H3JkEGgYhWhkR9wLHHEXC9FbWFnTlEkbKyZKWgWRLgf61E8zWmBuI6g5xKBph9ltg3NtZMVF8g==",
+=======
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.7.0.tgz",
+ "integrity": "sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==",
+>>>>>>> upstream/master
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
@@ -789,9 +889,9 @@
"doctrine": "^3.0.0",
"enquirer": "^2.3.5",
"eslint-scope": "^5.1.0",
- "eslint-utils": "^2.0.0",
- "eslint-visitor-keys": "^1.2.0",
- "espree": "^7.1.0",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^1.3.0",
+ "espree": "^7.2.0",
"esquery": "^1.2.0",
"esutils": "^2.0.2",
"file-entry-cache": "^5.0.1",
@@ -805,7 +905,7 @@
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
- "lodash": "^4.17.14",
+ "lodash": "^4.17.19",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
@@ -923,14 +1023,14 @@
"dev": true
},
"espree": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz",
- "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz",
+ "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==",
"dev": true,
"requires": {
- "acorn": "^7.2.0",
+ "acorn": "^7.3.1",
"acorn-jsx": "^5.2.0",
- "eslint-visitor-keys": "^1.2.0"
+ "eslint-visitor-keys": "^1.3.0"
}
},
"esprima": {
@@ -949,9 +1049,9 @@
},
"dependencies": {
"estraverse": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz",
- "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
"dev": true
}
}
@@ -1124,6 +1224,15 @@
"type-fest": "^0.8.1"
}
},
+ "glsl-tokenizer": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz",
+ "integrity": "sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==",
+ "dev": true,
+ "requires": {
+ "through2": "^0.6.3"
+ }
+ },
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
@@ -1351,11 +1460,12 @@
"dev": true
},
"jest-worker": {
- "version": "26.0.0",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.0.0.tgz",
- "integrity": "sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw==",
+ "version": "26.3.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz",
+ "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==",
"dev": true,
"requires": {
+ "@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^7.0.0"
}
@@ -1416,9 +1526,9 @@
}
},
"koa": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/koa/-/koa-2.12.1.tgz",
- "integrity": "sha512-NuYVKjnBxeEe19VljPO9yNcaKKVrMagcax3jjzZtOlxRY2nThWKQqgnI3Pr1OG7mFtvySoDRixoUWZIt6R9C3A==",
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.0.tgz",
+ "integrity": "sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ==",
"dev": true,
"requires": {
"accepts": "^1.3.5",
@@ -1591,26 +1701,14 @@
}
},
"koa-send": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.0.tgz",
- "integrity": "sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.1.tgz",
+ "integrity": "sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==",
"dev": true,
"requires": {
- "debug": "^3.1.0",
- "http-errors": "^1.6.3",
- "mz": "^2.7.0",
+ "debug": "^4.1.1",
+ "http-errors": "^1.7.3",
"resolve-path": "^1.4.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
}
},
"koa-static": {
@@ -1691,9 +1789,15 @@
}
},
"lodash": {
+<<<<<<< HEAD
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
+=======
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+>>>>>>> upstream/master
"dev": true
},
"lodash.assignwith": {
@@ -2269,6 +2373,15 @@
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
"dev": true
},
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
"raw-body": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz",
@@ -2380,24 +2493,30 @@
}
},
"rollup": {
+<<<<<<< HEAD
"version": "2.21.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.21.0.tgz",
"integrity": "sha512-BEGgy+wSzux7Ycq58pRiWEOBZaXRXTuvzl1gsm7gqmsAHxkWf9nyA5V2LN9fGSHhhDQd0/C13iRzSh4bbIpWZQ==",
+=======
+ "version": "2.26.3",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.3.tgz",
+ "integrity": "sha512-Mlt39/kL2rA9egcbQbaZV1SNVplGqYYhDDMcGgHPPE0tvM3R4GrB+IEdYy2QtTrdzMQx57ZcqDFf/KWWm8F+uw==",
+>>>>>>> upstream/master
"dev": true,
"requires": {
"fsevents": "~2.1.2"
}
},
"rollup-plugin-terser": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz",
- "integrity": "sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.0.tgz",
+ "integrity": "sha512-p/N3lLiFusCjYTLfVkoaiRTOGr5AESEaljMPH12MhOtoMkmTBhIAfuadrcWy4am1U0vU4WTxO9fi0K09O4CboQ==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.8.3",
- "jest-worker": "^26.0.0",
- "serialize-javascript": "^3.0.0",
- "terser": "^4.7.0"
+ "@babel/code-frame": "^7.10.4",
+ "jest-worker": "^26.2.1",
+ "serialize-javascript": "^4.0.0",
+ "terser": "^5.0.0"
}
},
"safe-buffer": {
@@ -2419,10 +2538,13 @@
"dev": true
},
"serialize-javascript": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz",
- "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==",
- "dev": true
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
},
"serve-index-75lb": {
"version": "2.0.1",
@@ -2508,9 +2630,15 @@
"dev": true
},
"skinview-utils": {
+<<<<<<< HEAD
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/skinview-utils/-/skinview-utils-0.5.6.tgz",
"integrity": "sha512-TkpkCkLHNmeltUrtmkMexS/6izDE6LD9VKrvEnKvAqByKcymiwfhFydzTCe1vsarnZK1VPtDbAvBh9/n6UkDLg=="
+=======
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/skinview-utils/-/skinview-utils-0.5.7.tgz",
+ "integrity": "sha512-XhOuCzvGoHuYOymfuZ8IJklVgqkYfusuyQSZMWiE/kluh89ZtBjS3cwoHIff1+Z5mAXHoa+Vkr0wN3JHJvF2ag=="
+>>>>>>> upstream/master
},
"slice-ansi": {
"version": "2.1.0",
@@ -2764,9 +2892,9 @@
}
},
"terser": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz",
- "integrity": "sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.1.0.tgz",
+ "integrity": "sha512-pwC1Jbzahz1ZPU87NQ8B3g5pKbhyJSiHih4gLH6WZiPU8mmS1IlGbB0A2Nuvkj/LCNsgIKctg6GkYwWCeTvXZQ==",
"dev": true,
"requires": {
"commander": "^2.20.0",
@@ -2781,9 +2909,9 @@
"dev": true
},
"thenify": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
- "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"dev": true,
"requires": {
"any-promise": "^1.0.0"
@@ -2799,9 +2927,9 @@
}
},
"three": {
- "version": "0.117.1",
- "resolved": "https://registry.npmjs.org/three/-/three-0.117.1.tgz",
- "integrity": "sha512-t4zeJhlNzUIj9+ub0l6nICVimSuRTZJOqvk3Rmlu+YGdTOJ49Wna8p7aumpkXJakJfITiybfpYE1XN1o1Z34UQ=="
+ "version": "0.120.0",
+ "resolved": "https://registry.npmjs.org/three/-/three-0.120.0.tgz",
+ "integrity": "sha512-Swffpi3EAHWkmqC1MagKEzR5XgwkDiyeWI3M7vkGbBc0xhq2LcQmJj5DqBruLkrgcZQ+fM/+fSQBU1tDvggO4A=="
},
"through": {
"version": "2.3.8",
@@ -2809,6 +2937,42 @@
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "dev": true,
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ }
+ }
+ },
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
@@ -2862,9 +3026,9 @@
}
},
"typescript": {
- "version": "3.9.6",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
- "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==",
+ "version": "3.9.7",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
+ "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
"dev": true
},
"typical": {
@@ -2976,6 +3140,12 @@
"mkdirp": "^0.5.1"
}
},
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
"ylru": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz",
diff --git a/package.json b/package.json
index 189f81a..58a11d0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "skinview3d",
- "version": "2.0.0-alpha.5",
+ "version": "2.0.0-alpha.8",
"description": "Three.js powered Minecraft skin viewer",
"main": "libs/skinview3d.js",
"type": "module",
@@ -11,10 +11,10 @@
"build": "npm run build:modules && npm run build:bundles",
"test:lint": "eslint --ext .ts src",
"test": "npm run test:lint",
- "dev:watch:modules": "tsc -w --declaration --sourceMap --outDir libs -p .",
- "dev:watch:bundles": "rollup -w -c",
+ "dev:watch:modules": "tsc -w --preserveWatchOutput --declaration --sourceMap --outDir libs -p .",
+ "dev:watch:bundles": "rollup -w --no-watch.clearScreen -c",
"dev:serve": "ws",
- "dev": "npm-run-all --parallel dev:watch:modules dev:watch:bundles dev:serve",
+ "dev": "npm-run-all --parallel dev:watch:bundles dev:serve",
"prepublishOnly": "npm run clean && npm run build"
},
"repository": {
@@ -38,21 +38,21 @@
"bundles"
],
"dependencies": {
- "skinview-utils": "^0.5.6",
- "three": "^0.117.1"
+ "skinview-utils": "^0.5.7",
+ "three": "^0.120.0"
},
"devDependencies": {
- "@rollup/plugin-node-resolve": "^8.4.0",
+ "@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-typescript": "^5.0.2",
- "@typescript-eslint/eslint-plugin": "^3.6.0",
- "@typescript-eslint/parser": "^3.6.0",
- "@yushijinhun/three-minifier-rollup": "^0.1.7",
- "eslint": "^7.4.0",
+ "@typescript-eslint/eslint-plugin": "^3.9.1",
+ "@typescript-eslint/parser": "^3.9.1",
+ "@yushijinhun/three-minifier-rollup": "^0.2.0-alpha.2",
+ "eslint": "^7.7.0",
"local-web-server": "^4.2.1",
"npm-run-all": "^4.1.5",
"rimraf": "^3.0.2",
- "rollup": "^2.21.0",
- "rollup-plugin-terser": "^6.1.0",
- "typescript": "^3.9.6"
+ "rollup": "^2.26.3",
+ "rollup-plugin-terser": "^7.0.0",
+ "typescript": "^3.9.7"
}
}
diff --git a/src/animation.ts b/src/animation.ts
index 641927e..872a25d 100644
--- a/src/animation.ts
+++ b/src/animation.ts
@@ -162,7 +162,7 @@ export const WalkingAnimation: Animation = (player, time) => {
export const RunningAnimation: Animation = (player, time) => {
const skin = player.skin;
- time *= 15;
+ time = time * 15 + Math.PI * 0.5;
// Leg swing with larger amplitude
skin.leftLeg.rotation.x = Math.cos(time + Math.PI) * 1.3;
diff --git a/src/fxaa.ts b/src/fxaa.ts
new file mode 100644
index 0000000..30fc2c0
--- /dev/null
+++ b/src/fxaa.ts
@@ -0,0 +1,45 @@
+import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
+import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
+import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
+import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";
+import { SkinViewer, SkinViewerOptions } from "./viewer.js";
+
+export class FXAASkinViewer extends SkinViewer {
+
+ readonly composer: EffectComposer;
+ readonly renderPass: RenderPass;
+ readonly fxaaPass: ShaderPass;
+
+ /**
+ * Note: FXAA doesn't work well with transparent backgrounds.
+ * It's recommended to use an opaque background and set `options.alpha` to false.
+ */
+ constructor(options: SkinViewerOptions = {}) {
+ super(options);
+ this.composer = new EffectComposer(this.renderer);
+ this.renderPass = new RenderPass(this.scene, this.camera);
+ this.fxaaPass = new ShaderPass(FXAAShader);
+ this.composer.addPass(this.renderPass);
+ this.composer.addPass(this.fxaaPass);
+ this.updateComposerSize();
+ }
+
+ setSize(width: number, height: number): void {
+ super.setSize(width, height);
+ if (this.composer !== undefined) {
+ this.updateComposerSize();
+ }
+ }
+
+ private updateComposerSize(): void {
+ this.composer.setSize(this.width, this.height);
+ const pixelRatio = this.renderer.getPixelRatio();
+ this.composer.setPixelRatio(pixelRatio);
+ this.fxaaPass.material.uniforms["resolution"].value.x = 1 / (this.width * pixelRatio);
+ this.fxaaPass.material.uniforms["resolution"].value.y = 1 / (this.height * pixelRatio);
+ }
+
+ render(): void {
+ this.composer.render();
+ }
+}
diff --git a/src/model.ts b/src/model.ts
index b38bc1f..675ca51 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -72,23 +72,29 @@ export class SkinObject extends Group {
constructor(texture: Texture) {
super();
- const layer1 = {
+ const layer1Material = new MeshBasicMaterial({
map: texture,
side: FrontSide
- };
- const layer2 = {
+ });
+ const layer2Material = new MeshBasicMaterial({
map: texture,
side: DoubleSide,
transparent: true,
- opacity: 1,
- alphaTest: 0.5
- }
+ alphaTest: 1e-5
+ });
- const layer1Material = new MeshBasicMaterial(layer1);
- const layer2Material = new MeshBasicMaterial(layer2);
+ const layer1MaterialBiased = layer1Material.clone();
+ layer1MaterialBiased.polygonOffset = true;
+ layer1MaterialBiased.polygonOffsetFactor = 1.0;
+ layer1MaterialBiased.polygonOffsetUnits = 1.0;
+
+ const layer2MaterialBiased = layer2Material.clone();
+ layer2MaterialBiased.polygonOffset = true;
+ layer2MaterialBiased.polygonOffsetFactor = 1.0;
+ layer2MaterialBiased.polygonOffsetUnits = 1.0;
// Head
- const headBox = new BoxGeometry(8, 8, 8, 0, 0, 0);
+ const headBox = new BoxGeometry(8, 8, 8);
setVertices(headBox,
toSkinVertices(8, 0, 16, 8),
toSkinVertices(16, 0, 24, 8),
@@ -99,7 +105,7 @@ export class SkinObject extends Group {
);
const headMesh = new Mesh(headBox, layer1Material);
- const head2Box = new BoxGeometry(9, 9, 9, 0, 0, 0);
+ const head2Box = new BoxGeometry(9, 9, 9);
setVertices(head2Box,
toSkinVertices(40, 0, 48, 8),
toSkinVertices(48, 0, 56, 8),
@@ -117,7 +123,7 @@ export class SkinObject extends Group {
this.add(this.head);
// Body
- const bodyBox = new BoxGeometry(8, 12, 4, 0, 0, 0);
+ const bodyBox = new BoxGeometry(8, 12, 4);
setVertices(bodyBox,
toSkinVertices(20, 16, 28, 20),
toSkinVertices(28, 16, 36, 20),
@@ -126,15 +132,9 @@ export class SkinObject extends Group {
toSkinVertices(28, 20, 32, 32),
toSkinVertices(32, 20, 40, 32)
);
- const bodyMesh = new Mesh(bodyBox, new MeshBasicMaterial({
- ...layer1,
- // this pulls bodyMesh towards the camera
- // so body is given priority over others in z-fighting
- polygonOffset: true,
- polygonOffsetUnits: -1
- }));
+ const bodyMesh = new Mesh(bodyBox, layer1Material);
- const body2Box = new BoxGeometry(9, 13.5, 4.5, 0, 0, 0);
+ const body2Box = new BoxGeometry(9, 13.5, 4.5);
setVertices(body2Box,
toSkinVertices(20, 32, 28, 36),
toSkinVertices(28, 32, 36, 36),
@@ -143,12 +143,7 @@ export class SkinObject extends Group {
toSkinVertices(28, 36, 32, 48),
toSkinVertices(32, 36, 40, 48)
);
- const body2Mesh = new Mesh(body2Box, new MeshBasicMaterial({
- ...layer2,
- // same as above
- polygonOffset: true,
- polygonOffsetUnits: -1
- }));
+ const body2Mesh = new Mesh(body2Box, layer2Material);
this.body = new BodyPart(bodyMesh, body2Mesh);
this.body.name = "body";
@@ -157,7 +152,7 @@ export class SkinObject extends Group {
this.add(this.body);
// Right Arm
- const rightArmBox = new BoxGeometry(1, 1, 1, 0, 0, 0); // w/d/h is model-related
+ const rightArmBox = new BoxGeometry();
const rightArmMesh = new Mesh(rightArmBox, layer1Material);
this.modelListeners.push(() => {
rightArmMesh.scale.x = this.slim ? 3 : 4;
@@ -186,8 +181,8 @@ export class SkinObject extends Group {
rightArmBox.elementsNeedUpdate = true;
});
- const rightArm2Box = new BoxGeometry(1, 1, 1, 0, 0, 0); // w/d/h is model-related
- const rightArm2Mesh = new Mesh(rightArm2Box, layer2Material);
+ const rightArm2Box = new BoxGeometry();
+ const rightArm2Mesh = new Mesh(rightArm2Box, layer2MaterialBiased);
rightArm2Mesh.renderOrder = 1;
this.modelListeners.push(() => {
rightArm2Mesh.scale.x = this.slim ? 3.375 : 4.5;
@@ -230,7 +225,7 @@ export class SkinObject extends Group {
this.add(this.rightArm);
// Left Arm
- const leftArmBox = new BoxGeometry(1, 1, 1, 0, 0, 0); // w/d/h is model-related
+ const leftArmBox = new BoxGeometry();
const leftArmMesh = new Mesh(leftArmBox, layer1Material);
this.modelListeners.push(() => {
leftArmMesh.scale.x = this.slim ? 3 : 4;
@@ -259,8 +254,8 @@ export class SkinObject extends Group {
leftArmBox.elementsNeedUpdate = true;
});
- const leftArm2Box = new BoxGeometry(1, 1, 1, 0, 0, 0); // w/d/h is model-related
- const leftArm2Mesh = new Mesh(leftArm2Box, layer2Material);
+ const leftArm2Box = new BoxGeometry();
+ const leftArm2Mesh = new Mesh(leftArm2Box, layer2MaterialBiased);
leftArm2Mesh.renderOrder = 1;
this.modelListeners.push(() => {
leftArm2Mesh.scale.x = this.slim ? 3.375 : 4.5;
@@ -303,7 +298,7 @@ export class SkinObject extends Group {
this.add(this.leftArm);
// Right Leg
- const rightLegBox = new BoxGeometry(4, 12, 4, 0, 0, 0);
+ const rightLegBox = new BoxGeometry(4, 12, 4);
setVertices(rightLegBox,
toSkinVertices(4, 16, 8, 20),
toSkinVertices(8, 16, 12, 20),
@@ -312,9 +307,9 @@ export class SkinObject extends Group {
toSkinVertices(8, 20, 12, 32),
toSkinVertices(12, 20, 16, 32)
);
- const rightLegMesh = new Mesh(rightLegBox, layer1Material);
+ const rightLegMesh = new Mesh(rightLegBox, layer1MaterialBiased);
- const rightLeg2Box = new BoxGeometry(4.5, 13.5, 4.5, 0, 0, 0);
+ const rightLeg2Box = new BoxGeometry(4.5, 13.5, 4.5);
setVertices(rightLeg2Box,
toSkinVertices(4, 32, 8, 36),
toSkinVertices(8, 32, 12, 36),
@@ -323,7 +318,7 @@ export class SkinObject extends Group {
toSkinVertices(8, 36, 12, 48),
toSkinVertices(12, 36, 16, 48)
);
- const rightLeg2Mesh = new Mesh(rightLeg2Box, layer2Material);
+ const rightLeg2Mesh = new Mesh(rightLeg2Box, layer2MaterialBiased);
rightLeg2Mesh.renderOrder = 1;
const rightLegPivot = new Group();
@@ -338,7 +333,7 @@ export class SkinObject extends Group {
this.add(this.rightLeg);
// Left Leg
- const leftLegBox = new BoxGeometry(4, 12, 4, 0, 0, 0);
+ const leftLegBox = new BoxGeometry(4, 12, 4);
setVertices(leftLegBox,
toSkinVertices(20, 48, 24, 52),
toSkinVertices(24, 48, 28, 52),
@@ -347,9 +342,9 @@ export class SkinObject extends Group {
toSkinVertices(24, 52, 28, 64),
toSkinVertices(28, 52, 32, 64)
);
- const leftLegMesh = new Mesh(leftLegBox, layer1Material);
+ const leftLegMesh = new Mesh(leftLegBox, layer1MaterialBiased);
- const leftLeg2Box = new BoxGeometry(4.5, 13.5, 4.5, 0, 0, 0);
+ const leftLeg2Box = new BoxGeometry(4.5, 13.5, 4.5);
setVertices(leftLeg2Box,
toSkinVertices(4, 48, 8, 52),
toSkinVertices(8, 48, 12, 52),
@@ -358,7 +353,7 @@ export class SkinObject extends Group {
toSkinVertices(8, 52, 12, 64),
toSkinVertices(12, 52, 16, 64)
);
- const leftLeg2Mesh = new Mesh(leftLeg2Box, layer2Material);
+ const leftLeg2Mesh = new Mesh(leftLeg2Box, layer2MaterialBiased);
leftLeg2Mesh.renderOrder = 1;
const leftLegPivot = new Group();
@@ -404,11 +399,16 @@ export class CapeObject extends Group {
constructor(texture: Texture) {
super();
- const capeMaterial = new MeshBasicMaterial({ map: texture, transparent: true, opacity: 1, side: DoubleSide, alphaTest: 0.5 });
+ const capeMaterial = new MeshBasicMaterial({
+ map: texture,
+ side: DoubleSide,
+ transparent: true,
+ alphaTest: 1e-5
+ });
// back = outside
// front = inside
- const capeBox = new BoxGeometry(10, 16, 1, 0, 0, 0);
+ const capeBox = new BoxGeometry(10, 16, 1);
setVertices(capeBox,
toCapeVertices(1, 0, 11, 1),
toCapeVertices(11, 0, 21, 1),
diff --git a/src/skinview3d.ts b/src/skinview3d.ts
index 366ed8e..2c75651 100644
--- a/src/skinview3d.ts
+++ b/src/skinview3d.ts
@@ -2,3 +2,4 @@ export * from "./model.js";
export * from "./viewer.js";
export * from "./orbit_controls.js";
export * from "./animation.js";
+export * from "./fxaa.js";
diff --git a/src/viewer.ts b/src/viewer.ts
index cf3b9ad..0cf65a5 100644
--- a/src/viewer.ts
+++ b/src/viewer.ts
@@ -5,7 +5,7 @@ import { PlayerObject } from "./model.js";
export type LoadOptions = {
/**
- * Whether to make the object visible after the texture is loaded. (default: true)
+ * Whether to make the object visible after the texture is loaded. Default is true.
*/
makeVisible?: boolean;
}
@@ -16,6 +16,29 @@ export type SkinViewerOptions = {
skin?: RemoteImage | TextureSource;
cape?: RemoteImage | TextureSource;
ears?: RemoteImage | TextureSource;
+
+ /**
+ * Whether the canvas contains an alpha buffer. Default is true.
+ * This option can be turned off if you use an opaque background.
+ */
+ alpha?: boolean;
+
+ /**
+ * Render target.
+ * A new canvas is created if this parameter is unspecified.
+ */
+ canvas?: HTMLCanvasElement;
+
+ /**
+ * Whether to preserve the buffers until manually cleared or overwritten. Default is false.
+ */
+ preserveDrawingBuffer?: boolean;
+
+ /**
+ * The initial value of `SkinViewer.renderPaused`. Default is false.
+ * If this option is true, rendering and animation loops will not start.
+ */
+ renderPaused?: boolean;
}
function toMakeVisible(options?: LoadOptions): boolean {
@@ -26,16 +49,16 @@ function toMakeVisible(options?: LoadOptions): boolean {
}
class SkinViewer {
- readonly domElement: Node;
+ readonly canvas: HTMLCanvasElement;
readonly scene: Scene;
readonly camera: PerspectiveCamera;
readonly renderer: WebGLRenderer;
readonly playerObject: PlayerObject;
readonly animations: RootAnimation = new RootAnimation();
- protected readonly skinCanvas: HTMLCanvasElement;
- protected readonly capeCanvas: HTMLCanvasElement;
- protected readonly earCanvas: HTMLCanvasElement;
+ readonly skinCanvas: HTMLCanvasElement;
+ readonly capeCanvas: HTMLCanvasElement;
+ readonly earCanvas: HTMLCanvasElement;
private readonly skinTexture: Texture;
private readonly capeTexture: Texture;
private readonly earTexture: Texture;
@@ -50,8 +73,8 @@ class SkinViewer {
private _disposed: boolean = false;
private _renderPaused: boolean = false;
- constructor(domElement: Node, options: SkinViewerOptions = {}) {
- this.domElement = domElement;
+ constructor(options: SkinViewerOptions = {}) {
+ this.canvas = options.canvas === undefined ? document.createElement("canvas") : options.canvas;
// texture
this.skinCanvas = document.createElement("canvas");
@@ -85,8 +108,13 @@ class SkinViewer {
this.camera.position.y = -12;
this.camera.position.z = 60;
- this.renderer = new WebGLRenderer({ alpha: true, logarithmicDepthBuffer: true });
- this.domElement.appendChild(this.renderer.domElement);
+ this.renderer = new WebGLRenderer({
+ canvas: this.canvas,
+ alpha: options.alpha !== false, // default: true
+ preserveDrawingBuffer: options.preserveDrawingBuffer === true // default: false
+
+ });
+ this.renderer.setPixelRatio(window.devicePixelRatio);
this.playerObject = new PlayerObject(this.skinTexture, this.capeTexture, this.earTexture);
this.playerObject.name = "player";
@@ -95,8 +123,6 @@ class SkinViewer {
this.playerObject.ears.visible = false;
this.scene.add(this.playerObject);
- window.requestAnimationFrame(() => this.draw());
-
if (options.skin !== undefined) {
this.loadSkin(options.skin);
}
@@ -112,6 +138,12 @@ class SkinViewer {
if (options.height !== undefined) {
this.height = options.height;
}
+
+ if (options.renderPaused === true) {
+ this._renderPaused = true;
+ } else {
+ window.requestAnimationFrame(() => this.draw());
+ }
}
protected skinLoaded(model: ModelType, options?: LoadOptions): void {
@@ -153,12 +185,16 @@ class SkinViewer {
return;
}
this.animations.runAnimationLoop(this.playerObject);
- this.doRender();
+ this.render();
this.animatedCape();
window.requestAnimationFrame(() => this.draw());
}
- protected doRender(): void {
+ /**
+ * Renders the scene to the canvas.
+ * This method does not change the animation progress.
+ */
+ render(): void {
this.renderer.render(this.scene, this.camera);
}
@@ -170,7 +206,6 @@ class SkinViewer {
dispose(): void {
this._disposed = true;
- this.domElement.removeChild(this.renderer.domElement);
this.renderer.dispose();
this.skinTexture.dispose();
this.capeTexture.dispose();
@@ -180,6 +215,11 @@ class SkinViewer {
return this._disposed;
}
+ /**
+ * Whether rendering and animations are paused.
+ * Setting this property to true will stop both rendering and animation loops.
+ * Setting it back to false will resume them.
+ */
get renderPaused(): boolean {
return this._renderPaused;
}