mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-12 01:58:45 +08:00
[ts][threejs] Add support for lighting and shadow. Upgraded three to 0.162.0. Added new constructor.
This commit is contained in:
parent
20827bf371
commit
7594c959dc
@ -500,6 +500,11 @@ rm "$ROOT/spine-ts/spine-threejs/example/assets/"*
|
||||
cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
cp -f ../raptor/export/raptor.atlas "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
cp -f ../raptor/export/raptor.png "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
|
||||
cp -f ../coin/export/coin-pro.json "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
cp -f ../coin/export/coin-pma.atlas "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
cp -f ../coin/export/coin-pma.png "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
|
||||
cp -f ../celestial-circus/export/* "$ROOT/spine-ts/spine-threejs/example/assets/"
|
||||
|
||||
rm "$ROOT/spine-ts/spine-player/example/assets/"*
|
||||
|
||||
@ -217,6 +217,9 @@
|
||||
<li>
|
||||
<a href="/spine-threejs/example/physics.html">Physics</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/spine-threejs/example/shadows.html">Shadows</a>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
1039
spine-ts/package-lock.json
generated
1039
spine-ts/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,25 +13,25 @@
|
||||
"postbuild": "npm run minify",
|
||||
"build:modules": "npx tsc -b -clean && npx tsc -b",
|
||||
"build:core:iife": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/iife/spine-core.js --format=iife --global-name=spine",
|
||||
"build:core:esm": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/esm/spine-core.esm.js --format=esm --global-name=spine",
|
||||
"build:core:esm": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/esm/spine-core.mjs --format=esm --global-name=spine",
|
||||
"build:canvas:iife": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/iife/spine-canvas.js --format=iife --global-name=spine",
|
||||
"build:canvas:esm": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/esm/spine-canvas.esm.js --format=esm --global-name=spine",
|
||||
"build:canvas:esm": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/esm/spine-canvas.mjs --format=esm --global-name=spine",
|
||||
"build:canvaskit:iife": "npx esbuild --bundle spine-canvaskit/src/index.ts --tsconfig=spine-canvaskit/tsconfig.json --sourcemap --outfile=spine-canvaskit/dist/iife/spine-canvaskit.js --external:canvaskit-wasm --format=iife --global-name=spine",
|
||||
"build:canvaskit:esm": "npx esbuild --bundle spine-canvaskit/src/index.ts --tsconfig=spine-canvaskit/tsconfig.json --sourcemap --outfile=spine-canvaskit/dist/esm/spine-canvaskit.esm.js --external:canvaskit-wasm --format=esm --global-name=spine",
|
||||
"build:canvaskit:esm": "npx esbuild --bundle spine-canvaskit/src/index.ts --tsconfig=spine-canvaskit/tsconfig.json --sourcemap --outfile=spine-canvaskit/dist/esm/spine-canvaskit.mjs --external:canvaskit-wasm --format=esm --global-name=spine",
|
||||
"build:webgl:iife": "npx esbuild --bundle spine-webgl/src/index.ts --tsconfig=spine-webgl/tsconfig.json --sourcemap --outfile=spine-webgl/dist/iife/spine-webgl.js --format=iife --global-name=spine",
|
||||
"build:webgl:esm": "npx esbuild --bundle spine-webgl/src/index.ts --tsconfig=spine-webgl/tsconfig.json --sourcemap --outfile=spine-webgl/dist/esm/spine-webgl.esm.js --format=esm --global-name=spine",
|
||||
"build:webgl:esm": "npx esbuild --bundle spine-webgl/src/index.ts --tsconfig=spine-webgl/tsconfig.json --sourcemap --outfile=spine-webgl/dist/esm/spine-webgl.mjs --format=esm --global-name=spine",
|
||||
"build:player:iife": "npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/iife/spine-player.js --format=iife --global-name=spine",
|
||||
"build:player:esm": "npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/esm/spine-player.esm.js --format=esm --global-name=spine",
|
||||
"build:player:esm": "npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/esm/spine-player.mjs --format=esm --global-name=spine",
|
||||
"build:player:css": "npx copyfiles -f spine-player/css/spine-player.css spine-player/dist/ && npx esbuild spine-player/dist/spine-player.css --minify --outfile=spine-player/dist/spine-player.min.css",
|
||||
"build:phaser:iife": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/iife/spine-phaser.js --external:Phaser --alias:phaser=Phaser --format=iife --global-name=spine",
|
||||
"build:phaser:esm": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/esm/spine-phaser.esm.js --external:Phaser --alias:phaser=Phaser --format=esm --global-name=spine",
|
||||
"build:phaser:esm": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/esm/spine-phaser.mjs --external:Phaser --alias:phaser=Phaser --format=esm --global-name=spine",
|
||||
"build:threejs:iife": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/iife/spine-threejs.js --external:three --format=iife --global-name=spine",
|
||||
"build:threejs:esm": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/esm/spine-threejs.esm.js --external:three --format=esm --global-name=spine",
|
||||
"build:threejs:esm": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/esm/spine-threejs.mjs --external:three --format=esm --global-name=spine",
|
||||
"build:pixi-v7:iife": "npx esbuild --bundle spine-pixi-v7/src/index.ts --tsconfig=spine-pixi-v7/tsconfig.json --sourcemap --outfile=spine-pixi-v7/dist/iife/spine-pixi-v7.js --external:@pixi/* --format=iife --global-name=spine",
|
||||
"build:pixi-v7:esm": "npx esbuild --bundle spine-pixi-v7/src/index.ts --tsconfig=spine-pixi-v7/tsconfig.json --sourcemap --outfile=spine-pixi-v7/dist/esm/spine-pixi-v7.esm.js --external:@pixi/* --format=esm --global-name=spine",
|
||||
"build:pixi-v7:esm": "npx esbuild --bundle spine-pixi-v7/src/index.ts --tsconfig=spine-pixi-v7/tsconfig.json --sourcemap --outfile=spine-pixi-v7/dist/esm/spine-pixi-v7.mjs --external:@pixi/* --format=esm --global-name=spine",
|
||||
"build:pixi-v8:iife": "npx esbuild --bundle spine-pixi-v8/src/index.ts --tsconfig=spine-pixi-v8/tsconfig.json --sourcemap --outfile=spine-pixi-v8/dist/iife/spine-pixi-v8.js --external:pixi.js --format=iife --global-name=spine",
|
||||
"build:pixi-v8:esm": "npx esbuild --bundle spine-pixi-v8/src/index.ts --tsconfig=spine-pixi-v8/tsconfig.json --sourcemap --outfile=spine-pixi-v8/dist/esm/spine-pixi-v8.esm.js --external:pixi.js --format=esm --global-name=spine",
|
||||
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-core/dist/esm/spine-core.esm.js --outfile=spine-core/dist/esm/spine-core.esm.min.js && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-canvas/dist/esm/spine-canvas.esm.js --outfile=spine-canvas/dist/esm/spine-canvas.esm.min.js && npx esbuild --minify spine-canvaskit/dist/iife/spine-canvaskit.js --outfile=spine-canvaskit/dist/iife/spine-canvaskit.min.js && npx esbuild --minify spine-canvaskit/dist/esm/spine-canvaskit.esm.js --outfile=spine-canvaskit/dist/esm/spine-canvaskit.esm.min.js && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-player/dist/esm/spine-player.esm.js --outfile=spine-player/dist/esm/spine-player.esm.min.js && npx esbuild --minify spine-phaser/dist/iife/spine-phaser.js --outfile=spine-phaser/dist/iife/spine-phaser.min.js && npx esbuild --minify spine-phaser/dist/esm/spine-phaser.esm.js --outfile=spine-phaser/dist/esm/spine-phaser.esm.min.js && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-webgl/dist/esm/spine-webgl.esm.js --outfile=spine-webgl/dist/esm/spine-webgl.esm.min.js && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js && npx esbuild --minify spine-threejs/dist/esm/spine-threejs.esm.js --outfile=spine-threejs/dist/esm/spine-threejs.esm.min.js && npx esbuild --minify spine-pixi-v7/dist/iife/spine-pixi-v7.js --outfile=spine-pixi-v7/dist/iife/spine-pixi-v7.min.js && npx esbuild --minify spine-pixi-v7/dist/esm/spine-pixi-v7.esm.js --outfile=spine-pixi-v7/dist/esm/spine-pixi-v7.esm.min.js && npx esbuild --minify spine-pixi-v8/dist/iife/spine-pixi-v8.js --outfile=spine-pixi-v8/dist/iife/spine-pixi-v8.min.js && npx esbuild --minify spine-pixi-v8/dist/esm/spine-pixi-v8.esm.js --outfile=spine-pixi-v8/dist/esm/spine-pixi-v8.esm.min.js",
|
||||
"build:pixi-v8:esm": "npx esbuild --bundle spine-pixi-v8/src/index.ts --tsconfig=spine-pixi-v8/tsconfig.json --sourcemap --outfile=spine-pixi-v8/dist/esm/spine-pixi-v8.mjs --external:pixi.js --format=esm --global-name=spine",
|
||||
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-core/dist/esm/spine-core.mjs --outfile=spine-core/dist/esm/spine-core.min.mjs && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-canvas/dist/esm/spine-canvas.mjs --outfile=spine-canvas/dist/esm/spine-canvas.min.mjs && npx esbuild --minify spine-canvaskit/dist/iife/spine-canvaskit.js --outfile=spine-canvaskit/dist/iife/spine-canvaskit.min.js && npx esbuild --minify spine-canvaskit/dist/esm/spine-canvaskit.mjs --outfile=spine-canvaskit/dist/esm/spine-canvaskit.min.mjs && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-player/dist/esm/spine-player.mjs --outfile=spine-player/dist/esm/spine-player.min.mjs && npx esbuild --minify spine-phaser/dist/iife/spine-phaser.js --outfile=spine-phaser/dist/iife/spine-phaser.min.js && npx esbuild --minify spine-phaser/dist/esm/spine-phaser.mjs --outfile=spine-phaser/dist/esm/spine-phaser.min.mjs && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-webgl/dist/esm/spine-webgl.mjs --outfile=spine-webgl/dist/esm/spine-webgl.min.mjs && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js && npx esbuild --minify spine-threejs/dist/esm/spine-threejs.mjs --outfile=spine-threejs/dist/esm/spine-threejs.min.mjs && npx esbuild --minify spine-pixi-v7/dist/iife/spine-pixi-v7.js --outfile=spine-pixi-v7/dist/iife/spine-pixi-v7.min.js && npx esbuild --minify spine-pixi-v7/dist/esm/spine-pixi-v7.mjs --outfile=spine-pixi-v7/dist/esm/spine-pixi-v7.min.mjs && npx esbuild --minify spine-pixi-v8/dist/iife/spine-pixi-v8.js --outfile=spine-pixi-v8/dist/iife/spine-pixi-v8.min.js && npx esbuild --minify spine-pixi-v8/dist/esm/spine-pixi-v8.mjs --outfile=spine-pixi-v8/dist/esm/spine-pixi-v8.min.mjs",
|
||||
"dev": "concurrently 'npx live-server' 'npm run dev:canvas' 'npm run dev:canvaskit' 'npm run dev:webgl' 'npm run dev:phaser' 'npm run dev:player' 'npm run dev:threejs' 'npm run dev:pixi-v7' 'npm run dev:pixi-v8' 'npm run dev:modules'",
|
||||
"dev:modules": "npm run build:modules -- --watch",
|
||||
"dev:canvas": "concurrently 'npm run build:canvas:iife -- --watch' 'npm run build:canvas:esm -- --watch'",
|
||||
@ -75,13 +75,11 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/offscreencanvas": "^2019.6.4",
|
||||
"@types/three": "^0.146.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
"esbuild": "^0.16.4",
|
||||
"live-server": "^1.2.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"three": "^0.146.0",
|
||||
"typescript": "5.6.2"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
19
spine-ts/spine-threejs/example/assets/coin-pma.atlas
Normal file
19
spine-ts/spine-threejs/example/assets/coin-pma.atlas
Normal file
@ -0,0 +1,19 @@
|
||||
coin-pma.png
|
||||
size: 1024, 1024
|
||||
filter: Linear, Linear
|
||||
pma: true
|
||||
coin-front-logo
|
||||
bounds: 2, 609, 305, 302
|
||||
coin-front-shine-logo
|
||||
bounds: 309, 629, 282, 282
|
||||
coin-front-shine-spineboy
|
||||
bounds: 2, 21, 282, 282
|
||||
coin-front-spineboy
|
||||
bounds: 2, 305, 305, 302
|
||||
coin-side-round
|
||||
bounds: 309, 345, 144, 282
|
||||
coin-side-straight
|
||||
bounds: 2, 2, 17, 282
|
||||
rotate: 90
|
||||
shine
|
||||
bounds: 593, 666, 72, 245
|
||||
BIN
spine-ts/spine-threejs/example/assets/coin-pma.png
Normal file
BIN
spine-ts/spine-threejs/example/assets/coin-pma.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 305 KiB |
259
spine-ts/spine-threejs/example/assets/coin-pro.json
Normal file
259
spine-ts/spine-threejs/example/assets/coin-pro.json
Normal file
@ -0,0 +1,259 @@
|
||||
{
|
||||
"skeleton": {
|
||||
"hash": "fKr+fe4rKEk",
|
||||
"spine": "4.2.22",
|
||||
"x": -152.5,
|
||||
"y": -151,
|
||||
"width": 305,
|
||||
"height": 302,
|
||||
"images": "./images/",
|
||||
"audio": ""
|
||||
},
|
||||
"bones": [
|
||||
{ "name": "root" },
|
||||
{ "name": "coin-front", "parent": "root" },
|
||||
{ "name": "clipping", "parent": "coin-front" },
|
||||
{ "name": "coin-sides", "parent": "root" },
|
||||
{ "name": "coin-side-round", "parent": "coin-sides" },
|
||||
{ "name": "coin-side-straight", "parent": "coin-sides" },
|
||||
{ "name": "shine", "parent": "root", "x": 243.14 }
|
||||
],
|
||||
"slots": [
|
||||
{ "name": "coin-side", "bone": "coin-side-straight", "color": "ffdb2fff", "attachment": "coin-side-straight" },
|
||||
{ "name": "coin-side-round", "bone": "coin-side-round", "color": "ffdb2fff", "attachment": "coin-side-round" },
|
||||
{ "name": "coin-front-texture", "bone": "coin-front", "color": "868686ff", "attachment": "coin-front-logo" },
|
||||
{ "name": "coin-front-shine", "bone": "coin-front", "color": "888888ff", "dark": "000000", "attachment": "coin-front-shine-logo", "blend": "additive" },
|
||||
{ "name": "clipping", "bone": "clipping", "attachment": "clipping" },
|
||||
{ "name": "shine", "bone": "shine", "color": "ffffff60", "attachment": "shine", "blend": "additive" }
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"name": "default",
|
||||
"attachments": {
|
||||
"clipping": {
|
||||
"clipping": {
|
||||
"type": "clipping",
|
||||
"end": "clipping",
|
||||
"vertexCount": 39,
|
||||
"vertices": [ 0.1, 140.26, -26.4, 138.14, -50.51, 131.25, -75.42, 119.06, -98.21, 101.04, -115.44, 82.22, -127.63, 62.08, -136.11, 39.03, -140.08, 19.68, -141.41, -0.19, -140.08, -22.98, -134.78, -45.5, -125.24, -66.44, -113.32, -84.19, -98.21, -101.95, -80.46, -116.52, -61.38, -127.39, -38.92, -134.81, -18.22, -139.27, -0.14, -140.58, 24.23, -138.48, 45.45, -132.46, 67.98, -122.5, 86.58, -110.19, 102.56, -95.25, 115.4, -78.75, 125.36, -61.72, 134, -42.33, 138.46, -22.15, 139.24, -0.15, 138.46, 20.29, 133.48, 39.94, 127.19, 58.54, 117.5, 76.1, 104.4, 92.86, 88.42, 108.32, 69.03, 121.42, 50.43, 130.85, 26.32, 137.4 ],
|
||||
"color": "ce3a3aff"
|
||||
}
|
||||
},
|
||||
"coin-front-shine": {
|
||||
"coin-front-shine-logo": { "width": 282, "height": 282 },
|
||||
"coin-front-shine-spineboy": { "width": 282, "height": 282 }
|
||||
},
|
||||
"coin-front-texture": {
|
||||
"coin-front-logo": { "width": 305, "height": 302 },
|
||||
"coin-front-spineboy": { "width": 305, "height": 302 }
|
||||
},
|
||||
"coin-side": {
|
||||
"coin-side-straight": { "x": 0.5, "width": 17, "height": 282 }
|
||||
},
|
||||
"coin-side-round": {
|
||||
"coin-side-round": { "x": -69.43, "width": 144, "height": 282 }
|
||||
},
|
||||
"shine": {
|
||||
"shine": { "y": 0.5, "scaleX": 1.6004, "scaleY": 1.6004, "width": 72, "height": 245 }
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"animations": {
|
||||
"animation": {
|
||||
"slots": {
|
||||
"coin-front-shine": {
|
||||
"rgba2": [
|
||||
{ "light": "7d7d7dff", "dark": "000000" },
|
||||
{ "time": 0.2667, "light": "000000ff", "dark": "7e7e7e" },
|
||||
{ "time": 0.664, "light": "000000ff", "dark": "000000" },
|
||||
{ "time": 1.0333, "light": "7f7f7fff", "dark": "000000" },
|
||||
{ "time": 1.3333, "light": "404040ff", "dark": "000000" },
|
||||
{ "time": 1.6, "light": "000000ff", "dark": "7e7e7e" },
|
||||
{ "time": 2.0022, "light": "000000ff", "dark": "000000" },
|
||||
{ "time": 2.4, "light": "7f7f7fff", "dark": "000000" },
|
||||
{ "time": 2.6667, "light": "7d7d7dff", "dark": "000000" }
|
||||
],
|
||||
"attachment": [
|
||||
{ "time": 0.6667, "name": "coin-front-shine-spineboy" },
|
||||
{ "time": 2, "name": "coin-front-shine-logo" }
|
||||
]
|
||||
},
|
||||
"coin-front-texture": {
|
||||
"rgba": [
|
||||
{ "color": "858585ff" },
|
||||
{ "time": 0.4, "color": "ffffffff" },
|
||||
{
|
||||
"time": 0.6696,
|
||||
"color": "858585ff",
|
||||
"curve": [ 0.725, 0.59, 0.892, 1, 0.725, 0.59, 0.892, 1, 0.725, 0.59, 0.892, 1, 0.725, 1, 0.892, 1 ]
|
||||
},
|
||||
{ "time": 0.9667, "color": "ffffffff" },
|
||||
{ "time": 1.3318, "color": "858585ff", "curve": "stepped" },
|
||||
{ "time": 1.3333, "color": "858585ff" },
|
||||
{ "time": 1.7333, "color": "ffffffff" },
|
||||
{ "time": 1.9982, "color": "858585ff", "curve": "stepped" },
|
||||
{ "time": 2.0022, "color": "858585ff" },
|
||||
{ "time": 2.3, "color": "ffffffff" },
|
||||
{ "time": 2.6667, "color": "858585ff" }
|
||||
],
|
||||
"attachment": [
|
||||
{ "time": 0.6667, "name": "coin-front-spineboy" },
|
||||
{ "time": 2, "name": "coin-front-logo" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"bones": {
|
||||
"coin-front": {
|
||||
"translate": [
|
||||
{},
|
||||
{ "time": 0.664, "x": 8.3, "curve": "stepped" },
|
||||
{
|
||||
"time": 0.6696,
|
||||
"x": -8.3,
|
||||
"curve": [ 0.794, -7.08, 1.167, 0, 0.794, 0, 1.167, 0 ]
|
||||
},
|
||||
{ "time": 1.3333 },
|
||||
{ "time": 1.9982, "x": 8.3, "curve": "stepped" },
|
||||
{ "time": 2.0022, "x": -8.3 },
|
||||
{ "time": 2.6667 }
|
||||
],
|
||||
"scale": [
|
||||
{
|
||||
"curve": [ 0.164, 1, 0.484, 0.091, 0.164, 1, 0.484, 1 ]
|
||||
},
|
||||
{ "time": 0.664, "x": 0, "curve": "stepped" },
|
||||
{
|
||||
"time": 0.6696,
|
||||
"x": 0.003,
|
||||
"curve": [ 0.786, 0.153, 1.167, 1, 0.786, 1, 1.167, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 1.3333,
|
||||
"curve": [ 1.442, 0.992, 1.858, 0.098, 1.442, 1, 1.858, 1 ]
|
||||
},
|
||||
{ "time": 1.9982, "x": 0.003, "curve": "stepped" },
|
||||
{
|
||||
"time": 2.0022,
|
||||
"x": 0.003,
|
||||
"curve": [ 2.123, 0.151, 2.501, 1, 2.123, 1, 2.501, 1 ]
|
||||
},
|
||||
{ "time": 2.6667 }
|
||||
]
|
||||
},
|
||||
"coin-side-round": {
|
||||
"translate": [
|
||||
{},
|
||||
{ "time": 0.664, "x": -6.75, "curve": "stepped" },
|
||||
{
|
||||
"time": 0.6696,
|
||||
"x": 7.03,
|
||||
"curve": [ 0.794, 5.99, 1.167, 0, 0.794, 0, 1.167, 0 ]
|
||||
},
|
||||
{ "time": 1.3333 },
|
||||
{ "time": 1.9982, "x": -6.75, "curve": "stepped" },
|
||||
{ "time": 2.0022, "x": 7.03 },
|
||||
{ "time": 2.6667 }
|
||||
],
|
||||
"scale": [
|
||||
{
|
||||
"curve": [ 0.085, 1, 0.207, 0.789, 0.085, 1, 0.207, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 0.3333,
|
||||
"x": 0.555,
|
||||
"curve": [ 0.449, 0.347, 0.567, 0.122, 0.449, 1, 0.567, 1 ]
|
||||
},
|
||||
{ "time": 0.664, "x": 0.014, "curve": "stepped" },
|
||||
{
|
||||
"time": 0.6696,
|
||||
"x": -0.028,
|
||||
"curve": [ 0.723, -0.126, 0.865, -0.367, 0.723, 1, 0.865, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 1,
|
||||
"x": -0.609,
|
||||
"curve": [ 1.053, -0.778, 1.29, -0.997, 1.053, 1, 1.29, 1 ]
|
||||
},
|
||||
{ "time": 1.3318, "x": -1, "curve": "stepped" },
|
||||
{
|
||||
"time": 1.3333,
|
||||
"curve": [ 1.384, 0.997, 1.439, 0.94, 1.384, 1, 1.439, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 1.5,
|
||||
"x": 0.852,
|
||||
"curve": [ 1.564, 0.748, 1.703, 0.509, 1.564, 1, 1.703, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 1.8,
|
||||
"x": 0.315,
|
||||
"curve": [ 1.873, 0.13, 1.987, 0.015, 1.873, 1, 1.987, 1 ]
|
||||
},
|
||||
{ "time": 1.9982, "x": 0.014, "curve": "stepped" },
|
||||
{
|
||||
"time": 2.0022,
|
||||
"x": -0.028,
|
||||
"curve": [ 2.039, -0.072, 2.123, -0.239, 2.039, 1, 2.123, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 2.2018,
|
||||
"x": -0.365,
|
||||
"curve": [ 2.269, -0.513, 2.337, -0.635, 2.269, 1, 2.337, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 2.4,
|
||||
"x": -0.731,
|
||||
"curve": [ 2.503, -0.871, 2.596, -0.961, 2.503, 1, 2.596, 1 ]
|
||||
},
|
||||
{
|
||||
"time": 2.6592,
|
||||
"x": -1,
|
||||
"curve": [ 2.661, -1, 2.665, 1, 2.661, 1, 2.665, 1 ]
|
||||
},
|
||||
{ "time": 2.6667 }
|
||||
]
|
||||
},
|
||||
"shine": {
|
||||
"translate": [
|
||||
{
|
||||
"curve": [ 0.167, 0, 0.5, -473.39, 0.167, 0, 0.5, 0 ]
|
||||
},
|
||||
{
|
||||
"time": 0.6667,
|
||||
"x": -473.39,
|
||||
"curve": [ 0.833, -473.39, 1.167, -33.16, 0.833, 0, 1.167, 0 ]
|
||||
},
|
||||
{
|
||||
"time": 1.3333,
|
||||
"x": -33.16,
|
||||
"curve": [ 1.5, -33.16, 1.833, -473.39, 1.5, 0, 1.833, 0 ]
|
||||
},
|
||||
{
|
||||
"time": 2,
|
||||
"x": -473.39,
|
||||
"curve": [ 2.167, -473.39, 2.5, 0, 2.167, 0, 2.5, 0 ]
|
||||
},
|
||||
{ "time": 2.6667 }
|
||||
]
|
||||
}
|
||||
},
|
||||
"drawOrder": [
|
||||
{
|
||||
"time": 0.6667,
|
||||
"offsets": [
|
||||
{ "slot": "coin-side", "offset": 2 }
|
||||
]
|
||||
},
|
||||
{ "time": 0.6696 },
|
||||
{
|
||||
"time": 1.9982,
|
||||
"offsets": [
|
||||
{ "slot": "coin-side", "offset": 2 }
|
||||
]
|
||||
},
|
||||
{ "time": 2.0022 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
101
spine-ts/spine-threejs/example/assets/raptor-pma.atlas
Normal file
101
spine-ts/spine-threejs/example/assets/raptor-pma.atlas
Normal file
@ -0,0 +1,101 @@
|
||||
raptor-pma.png
|
||||
size: 1024, 512
|
||||
filter: Linear, Linear
|
||||
pma: true
|
||||
scale: 0.5
|
||||
back-arm
|
||||
bounds: 829, 88, 46, 25
|
||||
rotate: 90
|
||||
back-bracer
|
||||
bounds: 195, 238, 39, 28
|
||||
rotate: 90
|
||||
back-hand
|
||||
bounds: 724, 140, 36, 34
|
||||
rotate: 90
|
||||
back-knee
|
||||
bounds: 760, 131, 49, 67
|
||||
rotate: 90
|
||||
back-thigh
|
||||
bounds: 225, 238, 39, 24
|
||||
rotate: 90
|
||||
eyes-open
|
||||
bounds: 975, 204, 47, 45
|
||||
front-arm
|
||||
bounds: 969, 112, 48, 26
|
||||
front-bracer
|
||||
bounds: 724, 97, 41, 29
|
||||
rotate: 90
|
||||
front-hand
|
||||
bounds: 251, 239, 41, 38
|
||||
front-open-hand
|
||||
bounds: 856, 76, 43, 44
|
||||
rotate: 90
|
||||
front-thigh
|
||||
bounds: 729, 178, 57, 29
|
||||
rotate: 90
|
||||
gun
|
||||
bounds: 894, 251, 107, 103
|
||||
gun-nohand
|
||||
bounds: 764, 241, 105, 102
|
||||
head
|
||||
bounds: 756, 345, 136, 149
|
||||
lower-leg
|
||||
bounds: 475, 237, 73, 98
|
||||
rotate: 90
|
||||
mouth-grind
|
||||
bounds: 975, 172, 47, 30
|
||||
mouth-smile
|
||||
bounds: 975, 140, 47, 30
|
||||
neck
|
||||
bounds: 366, 282, 18, 21
|
||||
raptor-back-arm
|
||||
bounds: 636, 97, 82, 86
|
||||
rotate: 90
|
||||
raptor-body
|
||||
bounds: 2, 2, 632, 233
|
||||
raptor-front-arm
|
||||
bounds: 871, 168, 81, 102
|
||||
rotate: 90
|
||||
raptor-front-leg
|
||||
bounds: 2, 237, 191, 257
|
||||
raptor-hindleg-back
|
||||
bounds: 195, 279, 169, 215
|
||||
raptor-horn
|
||||
bounds: 431, 312, 182, 80
|
||||
rotate: 90
|
||||
raptor-horn-back
|
||||
bounds: 513, 318, 176, 77
|
||||
rotate: 90
|
||||
raptor-jaw
|
||||
bounds: 894, 356, 126, 138
|
||||
raptor-jaw-tooth
|
||||
bounds: 294, 240, 37, 48
|
||||
rotate: 90
|
||||
raptor-mouth-inside
|
||||
bounds: 344, 241, 36, 41
|
||||
rotate: 90
|
||||
raptor-saddle-strap-back
|
||||
bounds: 575, 242, 54, 74
|
||||
raptor-saddle-strap-front
|
||||
bounds: 764, 182, 57, 95
|
||||
rotate: 90
|
||||
raptor-saddle-w-shadow
|
||||
bounds: 592, 323, 162, 171
|
||||
raptor-tail-shadow
|
||||
bounds: 366, 305, 189, 63
|
||||
rotate: 90
|
||||
raptor-tongue
|
||||
bounds: 387, 239, 86, 64
|
||||
stirrup-back
|
||||
bounds: 829, 136, 44, 35
|
||||
rotate: 90
|
||||
stirrup-front
|
||||
bounds: 866, 121, 45, 50
|
||||
rotate: 90
|
||||
stirrup-strap
|
||||
bounds: 918, 120, 49, 46
|
||||
torso
|
||||
bounds: 636, 181, 54, 91
|
||||
rotate: 90
|
||||
visor
|
||||
bounds: 631, 237, 131, 84
|
||||
BIN
spine-ts/spine-threejs/example/assets/raptor-pma.png
Normal file
BIN
spine-ts/spine-threejs/example/assets/raptor-pma.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 409 KiB |
95
spine-ts/spine-threejs/example/assets/spineboy-pma.atlas
Normal file
95
spine-ts/spine-threejs/example/assets/spineboy-pma.atlas
Normal file
@ -0,0 +1,95 @@
|
||||
spineboy-pma.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
pma: true
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 352, 7, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 862, 105, 47, 45
|
||||
eye-surprised
|
||||
bounds: 505, 79, 47, 45
|
||||
front-bracer
|
||||
bounds: 826, 66, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 786, 65, 38, 41
|
||||
front-fist-open
|
||||
bounds: 710, 51, 43, 44
|
||||
rotate: 90
|
||||
front-foot
|
||||
bounds: 210, 6, 63, 35
|
||||
front-shin
|
||||
bounds: 665, 128, 41, 92
|
||||
rotate: 90
|
||||
front-thigh
|
||||
bounds: 2, 2, 23, 56
|
||||
rotate: 90
|
||||
front-upper-arm
|
||||
bounds: 250, 205, 23, 49
|
||||
goggles
|
||||
bounds: 665, 171, 131, 83
|
||||
gun
|
||||
bounds: 798, 152, 105, 102
|
||||
head
|
||||
bounds: 2, 27, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 178, 246, 76
|
||||
hoverboard-thruster
|
||||
bounds: 722, 96, 30, 32
|
||||
rotate: 90
|
||||
hoverglow-small
|
||||
bounds: 275, 81, 137, 38
|
||||
mouth-grind
|
||||
bounds: 614, 97, 47, 30
|
||||
mouth-oooo
|
||||
bounds: 612, 65, 47, 30
|
||||
mouth-smile
|
||||
bounds: 661, 64, 47, 30
|
||||
muzzle-glow
|
||||
bounds: 382, 54, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 275, 54, 25, 105
|
||||
rotate: 90
|
||||
muzzle01
|
||||
bounds: 911, 95, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 792, 108, 68, 42
|
||||
muzzle03
|
||||
bounds: 956, 171, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 275, 7, 75, 45
|
||||
muzzle05
|
||||
bounds: 140, 3, 68, 38
|
||||
neck
|
||||
bounds: 250, 182, 18, 21
|
||||
portal-bg
|
||||
bounds: 140, 43, 133, 133
|
||||
portal-flare1
|
||||
bounds: 554, 65, 56, 30
|
||||
portal-flare2
|
||||
bounds: 759, 112, 57, 31
|
||||
rotate: 90
|
||||
portal-flare3
|
||||
bounds: 554, 97, 58, 30
|
||||
portal-shade
|
||||
bounds: 275, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 410, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 538, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 857, 67, 28, 36
|
||||
rear-foot
|
||||
bounds: 663, 96, 57, 30
|
||||
rear-shin
|
||||
bounds: 414, 86, 38, 89
|
||||
rotate: 90
|
||||
rear-thigh
|
||||
bounds: 756, 63, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 60, 5, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 905, 164, 49, 90
|
||||
BIN
spine-ts/spine-threejs/example/assets/spineboy-pma.png
Normal file
BIN
spine-ts/spine-threejs/example/assets/spineboy-pma.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 239 KiB |
8723
spine-ts/spine-threejs/example/assets/spineboy-pro.json
Normal file
8723
spine-ts/spine-threejs/example/assets/spineboy-pro.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
spine-ts/spine-threejs/example/assets/spineboy-pro.skel
Normal file
BIN
spine-ts/spine-threejs/example/assets/spineboy-pro.skel
Normal file
Binary file not shown.
94
spine-ts/spine-threejs/example/assets/spineboy.atlas
Normal file
94
spine-ts/spine-threejs/example/assets/spineboy.atlas
Normal file
@ -0,0 +1,94 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 352, 7, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 862, 105, 47, 45
|
||||
eye-surprised
|
||||
bounds: 505, 79, 47, 45
|
||||
front-bracer
|
||||
bounds: 826, 66, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 786, 65, 38, 41
|
||||
front-fist-open
|
||||
bounds: 710, 51, 43, 44
|
||||
rotate: 90
|
||||
front-foot
|
||||
bounds: 210, 6, 63, 35
|
||||
front-shin
|
||||
bounds: 665, 128, 41, 92
|
||||
rotate: 90
|
||||
front-thigh
|
||||
bounds: 2, 2, 23, 56
|
||||
rotate: 90
|
||||
front-upper-arm
|
||||
bounds: 250, 205, 23, 49
|
||||
goggles
|
||||
bounds: 665, 171, 131, 83
|
||||
gun
|
||||
bounds: 798, 152, 105, 102
|
||||
head
|
||||
bounds: 2, 27, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 178, 246, 76
|
||||
hoverboard-thruster
|
||||
bounds: 722, 96, 30, 32
|
||||
rotate: 90
|
||||
hoverglow-small
|
||||
bounds: 275, 81, 137, 38
|
||||
mouth-grind
|
||||
bounds: 614, 97, 47, 30
|
||||
mouth-oooo
|
||||
bounds: 612, 65, 47, 30
|
||||
mouth-smile
|
||||
bounds: 661, 64, 47, 30
|
||||
muzzle-glow
|
||||
bounds: 382, 54, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 275, 54, 25, 105
|
||||
rotate: 90
|
||||
muzzle01
|
||||
bounds: 911, 95, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 792, 108, 68, 42
|
||||
muzzle03
|
||||
bounds: 956, 171, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 275, 7, 75, 45
|
||||
muzzle05
|
||||
bounds: 140, 3, 68, 38
|
||||
neck
|
||||
bounds: 250, 182, 18, 21
|
||||
portal-bg
|
||||
bounds: 140, 43, 133, 133
|
||||
portal-flare1
|
||||
bounds: 554, 65, 56, 30
|
||||
portal-flare2
|
||||
bounds: 759, 112, 57, 31
|
||||
rotate: 90
|
||||
portal-flare3
|
||||
bounds: 554, 97, 58, 30
|
||||
portal-shade
|
||||
bounds: 275, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 410, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 538, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 857, 67, 28, 36
|
||||
rear-foot
|
||||
bounds: 663, 96, 57, 30
|
||||
rear-shin
|
||||
bounds: 414, 86, 38, 89
|
||||
rotate: 90
|
||||
rear-thigh
|
||||
bounds: 756, 63, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 60, 5, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 905, 164, 49, 90
|
||||
BIN
spine-ts/spine-threejs/example/assets/spineboy.png
Normal file
BIN
spine-ts/spine-threejs/example/assets/spineboy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 240 KiB |
@ -1,155 +1,159 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>spine-threejs</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>spine-threejs</title>
|
||||
<script src="https://unpkg.com/three@0.141.0/build/three.js"></script>
|
||||
<script src="../dist/iife/spine-threejs.js"></script>
|
||||
<script src="./OrbitalControls.js"></script>
|
||||
</head>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%
|
||||
}
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/",
|
||||
"spine-threejs": "../dist/esm/spine-threejs.mjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
(function () {
|
||||
let scene, camera, renderer;
|
||||
let skeletonMesh, cube, tailBone;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
<body>
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import * as spine from "spine-threejs";
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "raptor-pro.json";
|
||||
let atlasFile = skeletonFile.replace("-pro", "").replace("-ess", "").replace(".json", ".atlas");
|
||||
let animation = "walk";
|
||||
let scene, camera, renderer;
|
||||
let skeletonMesh, atlas, atlasLoader, geometry, material, cube, tailBone;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth, height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 200;
|
||||
camera.position.z = 800;
|
||||
scene = new THREE.Scene();
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(width, height);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
canvas = renderer.domElement;
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "raptor-pro.json";
|
||||
let atlasFile = skeletonFile.replace("-pro", "").replace("-ess", "").replace(".json", ".atlas");
|
||||
let animation = "walk";
|
||||
|
||||
// load the assets required to display the Raptor model
|
||||
assetManager = new spine.AssetManager(baseUrl);
|
||||
assetManager.loadText(skeletonFile);
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth, height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 200;
|
||||
camera.position.z = 800;
|
||||
scene = new THREE.Scene();
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(width, height);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
canvas = renderer.domElement;
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
// load the assets required to display the Raptor model
|
||||
assetManager = new spine.AssetManager(baseUrl);
|
||||
assetManager.loadText(skeletonFile);
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
|
||||
function load(name, scale) {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
function load(name, scale) {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(assetManager.require(skeletonFile));
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh(skeletonData, (parameters) => {
|
||||
parameters.depthTest = true;
|
||||
parameters.depthWrite = true;
|
||||
parameters.alphaTest = 0.001;
|
||||
});
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
skeletonMesh.position.x = 120;
|
||||
skeletonMesh.position.y = -20;
|
||||
skeletonMesh.position.z = 10;
|
||||
scene.add(skeletonMesh);
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(assetManager.require(skeletonFile));
|
||||
|
||||
// Add a wireframe cube which will be positioned at the tail bone
|
||||
geometry = new THREE.BoxGeometry(20, 20, 20);
|
||||
material = new THREE.MeshBasicMaterial({ color: 0xff00, wireframe: true });
|
||||
cube = new THREE.Mesh(geometry, material);
|
||||
scene.add(cube);
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh({ skeletonData });
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
skeletonMesh.position.x = 120;
|
||||
skeletonMesh.position.y = -20;
|
||||
skeletonMesh.position.z = 10;
|
||||
scene.add(skeletonMesh);
|
||||
|
||||
// Get the tail bone
|
||||
tailBone = skeletonMesh.skeleton.findBone("tail10");
|
||||
// Add a wireframe cube which will be positioned at the tail bone
|
||||
geometry = new THREE.BoxGeometry(20, 20, 20);
|
||||
material = new THREE.MeshBasicMaterial({ color: 0xff00, wireframe: true });
|
||||
cube = new THREE.Mesh(geometry, material);
|
||||
scene.add(cube);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
lastFrameTime = now;
|
||||
|
||||
// resize canvas to use full page, adjust camera/renderer
|
||||
resize();
|
||||
|
||||
// Update orbital controls
|
||||
controls.update();
|
||||
|
||||
// update the animation
|
||||
skeletonMesh.update(delta);
|
||||
|
||||
// Get the tail bone coordinates in the skeleton's local coordinate space.
|
||||
let position = new THREE.Vector3(tailBone.worldX, tailBone.worldY, 0);
|
||||
|
||||
// Convert the tail bone coordinates to world coordinates.
|
||||
skeletonMesh.localToWorld(position)
|
||||
|
||||
// Set the tail bone coordinates as the cube's position.
|
||||
cube.position.set(position.x, position.y, position.z);
|
||||
|
||||
// render the scene
|
||||
renderer.render(scene, camera);
|
||||
// Get the tail bone
|
||||
tailBone = skeletonMesh.skeleton.findBone("tail10");
|
||||
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
lastFrameTime = now;
|
||||
|
||||
// resize canvas to use full page, adjust camera/renderer
|
||||
resize();
|
||||
|
||||
// Update orbital controls
|
||||
controls.update();
|
||||
|
||||
// update the animation
|
||||
skeletonMesh.update(delta);
|
||||
|
||||
// Get the tail bone coordinates in the skeleton's local coordinate space.
|
||||
let position = new THREE.Vector3(tailBone.worldX, tailBone.worldY, 0);
|
||||
|
||||
// Convert the tail bone coordinates to world coordinates.
|
||||
skeletonMesh.localToWorld(position)
|
||||
|
||||
// Set the tail bone coordinates as the cube's position.
|
||||
cube.position.set(position.x, position.y, position.z);
|
||||
|
||||
// render the scene
|
||||
renderer.render(scene, camera);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
|
||||
init();
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
init();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -2,50 +2,62 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>spine-threejs</title>
|
||||
<script src="https://unpkg.com/three@0.141.0/build/three.js"></script>
|
||||
<script src="../dist/iife/spine-threejs.js"></script>
|
||||
<script src="./OrbitalControls.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/",
|
||||
"spine-threejs": "../dist/esm/spine-threejs.mjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
(function () {
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import * as spine from "spine-threejs";
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "raptor-pro.json";
|
||||
let atlasFile = skeletonFile
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh;
|
||||
let atlas;
|
||||
let atlasLoader;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "raptor-pro.json";
|
||||
let atlasFile = skeletonFile
|
||||
.replace("-pro", "")
|
||||
.replace("-ess", "")
|
||||
.replace(".json", ".atlas");
|
||||
let animation = "walk";
|
||||
let animation = "walk";
|
||||
|
||||
function init() {
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth,
|
||||
height = window.innerHeight;
|
||||
height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 100;
|
||||
camera.position.z = 400;
|
||||
@ -62,53 +74,46 @@
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
}
|
||||
|
||||
function load(name, scale) {
|
||||
function load(name, scale) {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
// Add a box to the scene to which we attach the skeleton mesh
|
||||
geometry = new THREE.BoxGeometry(200, 200, 200);
|
||||
material = new THREE.MeshBasicMaterial({
|
||||
// Add a box to the scene to which we attach the skeleton mesh
|
||||
geometry = new THREE.BoxGeometry(200, 200, 200);
|
||||
material = new THREE.MeshBasicMaterial({
|
||||
color: 0xff0000,
|
||||
wireframe: true,
|
||||
});
|
||||
mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
});
|
||||
mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(
|
||||
assetManager.require(skeletonFile)
|
||||
);
|
||||
);
|
||||
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh(
|
||||
skeletonData,
|
||||
(parameters) => {
|
||||
parameters.depthTest = true;
|
||||
parameters.depthWrite = true;
|
||||
parameters.alphaTest = 0.001;
|
||||
}
|
||||
);
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
mesh.add(skeletonMesh);
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh({ skeletonData });
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
mesh.add(skeletonMesh);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
@ -127,24 +132,24 @@
|
||||
renderer.render(scene, camera);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
}
|
||||
|
||||
function resize() {
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
init();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -2,33 +2,43 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>spine-threejs</title>
|
||||
<script src="https://unpkg.com/three@0.141.0/build/three.js"></script>
|
||||
<script src="../dist/iife/spine-threejs.js"></script>
|
||||
<script src="./OrbitalControls.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/",
|
||||
"spine-threejs": "../dist/esm/spine-threejs.mjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
(function () {
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh;
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import * as spine from "spine-threejs";
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh, atlas, atlasLoader;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
@ -95,11 +105,10 @@
|
||||
// Provide a custom vertex/fragment shader pair that supports
|
||||
// the logarithmic depth buffer.
|
||||
// See https://discourse.threejs.org/t/shadermaterial-render-order-with-logarithmicdepthbuffer-is-wrong/49221/3
|
||||
skeletonMesh = new spine.SkeletonMesh(
|
||||
skeletonMesh = new spine.SkeletonMesh({
|
||||
skeletonData,
|
||||
(materialParameters) => {
|
||||
materialFactory: (materialParameters) => {
|
||||
materialParameters.vertexShader = `
|
||||
attribute vec4 color;
|
||||
varying vec2 vUv;
|
||||
varying vec4 vColor;
|
||||
|
||||
@ -130,12 +139,14 @@
|
||||
|
||||
gl_FragColor = texture2D(map, vUv)*vColor;
|
||||
#ifdef USE_SPINE_ALPHATEST
|
||||
if (gl_FragColor.a < alphaTest) discard;
|
||||
if (gl_FragColor.a < alphaTest) discard;
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
|
||||
return new spine.SkeletonMeshMaterial(materialParameters);
|
||||
}
|
||||
);
|
||||
});
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
mesh.add(skeletonMesh);
|
||||
|
||||
@ -180,7 +191,7 @@
|
||||
}
|
||||
|
||||
init();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -2,149 +2,165 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>spine-threejs</title>
|
||||
<script src="https://unpkg.com/three@0.141.0/build/three.js"></script>
|
||||
<script src="../dist/iife/spine-threejs.js"></script>
|
||||
<script src="./OrbitalControls.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.159.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.159.0/examples/jsm/",
|
||||
"spine-threejs": "../dist/esm/spine-threejs.mjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
(function () {
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import * as spine from "spine-threejs";
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
let pma = false;
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "celestial-circus-pro.json";
|
||||
let atlasFile = `celestial-circus${pma ? "-pma" : ""}.atlas`;
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh, atlas, atlasLoader;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth,
|
||||
height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 0;
|
||||
camera.position.z = 800;
|
||||
scene = new THREE.Scene();
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(width, height);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
canvas = renderer.domElement;
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
let pma = true;
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "celestial-circus-pro.json";
|
||||
let atlasFile = `celestial-circus${pma ? "-pma" : ""}.atlas`;
|
||||
|
||||
// load the assets required to display the Raptor model
|
||||
assetManager = new spine.AssetManager(baseUrl, undefined, pma);
|
||||
assetManager.loadText(skeletonFile);
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth,
|
||||
height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 0;
|
||||
camera.position.z = 800;
|
||||
scene = new THREE.Scene();
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(width, height);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
canvas = renderer.domElement;
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
// load the assets required to display the Raptor model
|
||||
assetManager = new spine.AssetManager(baseUrl, undefined, pma);
|
||||
assetManager.loadText(skeletonFile);
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
|
||||
function load(name, scale) {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
// Add a box to the scene to which we attach the skeleton mesh
|
||||
geometry = new THREE.BoxGeometry(200, 200, 200);
|
||||
material = new THREE.MeshBasicMaterial({
|
||||
color: 0xff0000,
|
||||
wireframe: true,
|
||||
});
|
||||
mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
function load(name, scale) {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
// Add a box to the scene to which we attach the skeleton mesh
|
||||
geometry = new THREE.BoxGeometry(200, 200, 200);
|
||||
material = new THREE.MeshBasicMaterial({
|
||||
color: 0xff0000,
|
||||
wireframe: true,
|
||||
});
|
||||
mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(
|
||||
assetManager.require(skeletonFile)
|
||||
);
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(
|
||||
assetManager.require(skeletonFile)
|
||||
);
|
||||
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh(
|
||||
skeletonMesh = new spine.SkeletonMesh({
|
||||
skeletonData,
|
||||
(parameters) => {
|
||||
parameters.depthTest = true;
|
||||
parameters.depthWrite = true;
|
||||
parameters.alphaTest = 0.001;
|
||||
}
|
||||
);
|
||||
materialFactory: (parameters) => {
|
||||
return new THREE.MeshBasicMaterial({
|
||||
...parameters,
|
||||
// transparent: true,
|
||||
// depthWrite: true,
|
||||
// depthTest: true,
|
||||
// alphaTest: 0.001,
|
||||
// vertexColors: true,
|
||||
});
|
||||
},
|
||||
twoColorTint: false,
|
||||
});
|
||||
skeletonMesh.state.setAnimation(0, "swing", true);
|
||||
skeletonMesh.state.setAnimation(1, "eyeblink-long", true);
|
||||
mesh.add(skeletonMesh);
|
||||
|
||||
skeletonMesh.position.y = -300;
|
||||
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
lastFrameTime = now;
|
||||
|
||||
// resize canvas to use full page, adjust camera/renderer
|
||||
resize();
|
||||
|
||||
// Update orbital controls
|
||||
controls.update();
|
||||
|
||||
// update the animation
|
||||
skeletonMesh.update(delta);
|
||||
|
||||
// render the scene
|
||||
renderer.render(scene, camera);
|
||||
skeletonMesh.position.y = -200;
|
||||
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
lastFrameTime = now;
|
||||
|
||||
// resize canvas to use full page, adjust camera/renderer
|
||||
resize();
|
||||
|
||||
// Update orbital controls
|
||||
controls.update();
|
||||
|
||||
// update the animation
|
||||
skeletonMesh.update(delta);
|
||||
|
||||
// render the scene
|
||||
renderer.render(scene, camera);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
init();
|
||||
|
||||
init();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
276
spine-ts/spine-threejs/example/shadows.html
Normal file
276
spine-ts/spine-threejs/example/shadows.html
Normal file
@ -0,0 +1,276 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>spine-threejs</title>
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/",
|
||||
"spine-threejs": "../dist/esm/spine-threejs.mjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import * as spine from "spine-threejs";
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
let scene, camera, renderer;
|
||||
let geometry, material, mesh, skeletonMesh, atlas, atlasLoader, atlas2, atlasLoader2, skeletonMesh2, atlas3, atlasLoader3, skeletonMesh3;
|
||||
let assetManager;
|
||||
let canvas;
|
||||
let controls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
|
||||
let pma = false;
|
||||
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "raptor-pro.json";
|
||||
let atlasFile = "raptor.atlas";
|
||||
let animation = "walk";
|
||||
|
||||
let skeletonFile2 = "celestial-circus-pro.json";
|
||||
let atlasFile2 = "celestial-circus.atlas";
|
||||
let animation2 = "swing";
|
||||
|
||||
let skeletonFile3 = "coin-pro.json";
|
||||
let atlasFile3 = "coin-pma.atlas";
|
||||
let animation3 = "animation";
|
||||
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth,
|
||||
height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 700;
|
||||
camera.position.z = 300;
|
||||
camera.lookAt(new THREE.Vector3(0, 0, 0))
|
||||
scene = new THREE.Scene();
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(width, height);
|
||||
renderer.shadowMap.enabled = true
|
||||
|
||||
document.body.appendChild(renderer.domElement);
|
||||
canvas = renderer.domElement;
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
|
||||
// LIGHTS - Ambient
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 1.0)
|
||||
scene.add(ambientLight)
|
||||
|
||||
// LIGHTS - spotLight
|
||||
const spotLight = new THREE.SpotLight(0xffffff, 5, 1200, Math.PI / 4, 0, 0)
|
||||
spotLight.position.set(0, 1000, 0)
|
||||
spotLight.castShadow = true
|
||||
spotLight.shadow.mapSize.set(8192, 8192)
|
||||
spotLight.shadow.bias = -0.00001;
|
||||
|
||||
scene.add(spotLight)
|
||||
|
||||
const spotLightHepler = new THREE.SpotLightHelper(spotLight)
|
||||
scene.add(spotLightHepler)
|
||||
|
||||
// BOX
|
||||
const boxGeometry = new THREE.BoxGeometry(400, 10, 10)
|
||||
const boxMaterial = new THREE.MeshStandardMaterial({
|
||||
transparent: true,
|
||||
metalness: 0.5,
|
||||
roughness: 1,
|
||||
opacity: 1,
|
||||
})
|
||||
const box = new THREE.Mesh(boxGeometry, boxMaterial)
|
||||
box.position.set(0, 300, -200)
|
||||
box.castShadow = true
|
||||
box.receiveShadow = true
|
||||
scene.add(box)
|
||||
|
||||
// PLANE
|
||||
const planeGeometry = new THREE.PlaneGeometry(2000, 2000)
|
||||
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x213573 })
|
||||
const plane = new THREE.Mesh(planeGeometry, planeMaterial)
|
||||
plane.rotation.x = -Math.PI / 2
|
||||
plane.material.side = THREE.DoubleSide
|
||||
plane.receiveShadow = true
|
||||
scene.add(plane)
|
||||
|
||||
// load the assets required to display the Raptor model
|
||||
assetManager = new spine.AssetManager(baseUrl, undefined, pma);
|
||||
assetManager.loadText(skeletonFile);
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
|
||||
assetManager.loadText(skeletonFile2);
|
||||
assetManager.loadTextureAtlas(atlasFile2);
|
||||
|
||||
assetManager.loadText(skeletonFile3);
|
||||
assetManager.loadTextureAtlas(atlasFile3);
|
||||
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
function load(name, scale) {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
atlas2 = assetManager.require(atlasFile2);
|
||||
atlas3 = assetManager.require(atlasFile3);
|
||||
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
atlasLoader2 = new spine.AtlasAttachmentLoader(atlas2);
|
||||
atlasLoader3 = new spine.AtlasAttachmentLoader(atlas3);
|
||||
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
let skeletonJson2 = new spine.SkeletonJson(atlasLoader2);
|
||||
let skeletonJson3 = new spine.SkeletonJson(atlasLoader3);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(
|
||||
assetManager.require(skeletonFile)
|
||||
);
|
||||
skeletonJson2.scale = 0.4;
|
||||
let skeletonData2 = skeletonJson2.readSkeletonData(
|
||||
assetManager.require(skeletonFile2)
|
||||
);
|
||||
|
||||
skeletonJson3.scale = 0.4;
|
||||
let skeletonData3 = skeletonJson3.readSkeletonData(
|
||||
assetManager.require(skeletonFile3)
|
||||
);
|
||||
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh({
|
||||
skeletonData,
|
||||
materialFactory: param => {
|
||||
param.alphaTest = 0.001;
|
||||
return new THREE.MeshStandardMaterial(param);
|
||||
}
|
||||
});
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
scene.add(skeletonMesh);
|
||||
skeletonMesh.update(0)
|
||||
|
||||
skeletonMesh.rotation.set(-Math.PI / 2, 0, 0);
|
||||
skeletonMesh.position.set(0, 100, 100);
|
||||
|
||||
skeletonMesh.castShadow = true;
|
||||
skeletonMesh.receiveShadow = true;
|
||||
|
||||
skeletonMesh2 = new spine.SkeletonMesh({
|
||||
skeletonData: skeletonData2,
|
||||
premultipliedAlpha: true,
|
||||
materialFactory: param => {
|
||||
param.alphaTest = 0.001;
|
||||
param.premultipliedAlpha = true;
|
||||
return new THREE.MeshStandardMaterial(param);
|
||||
}
|
||||
});
|
||||
|
||||
skeletonMesh2.state.setAnimation(0, animation2, true);
|
||||
scene.add(skeletonMesh2);
|
||||
skeletonMesh2.update(0)
|
||||
|
||||
skeletonMesh2.rotation.set(-Math.PI / 2.4, 0, 0);
|
||||
skeletonMesh2.position.set(0, 150, 100);
|
||||
|
||||
skeletonMesh2.castShadow = true;
|
||||
skeletonMesh2.receiveShadow = true;
|
||||
|
||||
|
||||
|
||||
skeletonMesh3 = new spine.SkeletonMesh({
|
||||
skeletonData: skeletonData3,
|
||||
premultipliedAlpha: true,
|
||||
twoColorTint: true,
|
||||
materialFactory: param => {
|
||||
param.alphaTest = 0.001;
|
||||
param.premultipliedAlpha = true;
|
||||
return new THREE.MeshStandardMaterial(param);
|
||||
}
|
||||
});
|
||||
|
||||
skeletonMesh3.state.setAnimation(0, animation3, true);
|
||||
scene.add(skeletonMesh3);
|
||||
skeletonMesh3.update(0)
|
||||
|
||||
skeletonMesh3.rotation.set(-Math.PI / 2.4, 0, 0);
|
||||
skeletonMesh3.position.set(100, 150, 50);
|
||||
|
||||
skeletonMesh3.castShadow = true;
|
||||
skeletonMesh3.receiveShadow = true;
|
||||
|
||||
skeletonMesh3.update(1.5);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
lastFrameTime = now;
|
||||
|
||||
// resize canvas to use full page, adjust camera/renderer
|
||||
resize();
|
||||
|
||||
// Update orbital controls
|
||||
controls.update();
|
||||
|
||||
// update the animation
|
||||
skeletonMesh.update(delta);
|
||||
skeletonMesh2.update(delta);
|
||||
skeletonMesh3.update(delta);
|
||||
|
||||
// render the scene
|
||||
renderer.render(scene, camera);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
6
spine-ts/spine-threejs/example/typescript/README.md
Normal file
6
spine-ts/spine-threejs/example/typescript/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# spine-threejs TypeScript
|
||||
Minimal example project using Pixi, spine-pixi, and TypeScript via NPM and [esbuild](https://esbuild.github.io/).
|
||||
|
||||
1. Install dependencies: `npm install`
|
||||
2. Build bundle: `npm run build`
|
||||
3. Development (run server and recompile in watch mode): `npm run dev`
|
||||
9185
spine-ts/spine-threejs/example/typescript/assets/raptor-pro.json
Normal file
9185
spine-ts/spine-threejs/example/typescript/assets/raptor-pro.json
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,93 @@
|
||||
raptor.png
|
||||
size: 1024, 512
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
back-arm
|
||||
bounds: 895, 295, 46, 25
|
||||
back-bracer
|
||||
bounds: 992, 216, 39, 28
|
||||
rotate: 90
|
||||
back-hand
|
||||
bounds: 594, 58, 36, 34
|
||||
back-knee
|
||||
bounds: 729, 86, 49, 67
|
||||
rotate: 90
|
||||
back-thigh
|
||||
bounds: 379, 2, 39, 24
|
||||
eyes-open
|
||||
bounds: 902, 194, 47, 45
|
||||
rotate: 90
|
||||
front-arm
|
||||
bounds: 945, 306, 48, 26
|
||||
front-bracer
|
||||
bounds: 949, 197, 41, 29
|
||||
front-hand
|
||||
bounds: 949, 266, 41, 38
|
||||
front-open-hand
|
||||
bounds: 875, 148, 43, 44
|
||||
front-thigh
|
||||
bounds: 793, 171, 57, 29
|
||||
rotate: 90
|
||||
gun
|
||||
bounds: 379, 28, 107, 103
|
||||
rotate: 90
|
||||
gun-nohand
|
||||
bounds: 487, 87, 105, 102
|
||||
head
|
||||
bounds: 807, 361, 136, 149
|
||||
lower-leg
|
||||
bounds: 827, 195, 73, 98
|
||||
mouth-grind
|
||||
bounds: 920, 145, 47, 30
|
||||
rotate: 90
|
||||
mouth-smile
|
||||
bounds: 992, 257, 47, 30
|
||||
rotate: 90
|
||||
neck
|
||||
bounds: 359, 114, 18, 21
|
||||
raptor-back-arm
|
||||
bounds: 653, 142, 82, 86
|
||||
raptor-body
|
||||
bounds: 2, 277, 632, 233
|
||||
raptor-front-arm
|
||||
bounds: 484, 4, 81, 102
|
||||
rotate: 90
|
||||
raptor-front-leg
|
||||
bounds: 2, 18, 191, 257
|
||||
raptor-hindleg-back
|
||||
bounds: 636, 295, 169, 215
|
||||
raptor-horn
|
||||
bounds: 195, 22, 182, 80
|
||||
raptor-horn-back
|
||||
bounds: 945, 334, 176, 77
|
||||
rotate: 90
|
||||
raptor-jaw
|
||||
bounds: 359, 137, 126, 138
|
||||
raptor-jaw-tooth
|
||||
bounds: 895, 322, 37, 48
|
||||
rotate: 90
|
||||
raptor-mouth-inside
|
||||
bounds: 949, 228, 36, 41
|
||||
rotate: 90
|
||||
raptor-saddle-strap-back
|
||||
bounds: 653, 86, 54, 74
|
||||
rotate: 90
|
||||
raptor-saddle-strap-front
|
||||
bounds: 594, 94, 57, 95
|
||||
raptor-saddle-w-shadow
|
||||
bounds: 195, 104, 162, 171
|
||||
raptor-tail-shadow
|
||||
bounds: 636, 230, 189, 63
|
||||
raptor-tongue
|
||||
bounds: 807, 295, 86, 64
|
||||
stirrup-back
|
||||
bounds: 952, 151, 44, 35
|
||||
rotate: 90
|
||||
stirrup-front
|
||||
bounds: 902, 243, 45, 50
|
||||
stirrup-strap
|
||||
bounds: 824, 147, 49, 46
|
||||
torso
|
||||
bounds: 737, 137, 54, 91
|
||||
visor
|
||||
bounds: 487, 191, 131, 84
|
||||
BIN
spine-ts/spine-threejs/example/typescript/assets/raptor.png
Normal file
BIN
spine-ts/spine-threejs/example/typescript/assets/raptor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 413 KiB |
12
spine-ts/spine-threejs/example/typescript/index.html
Normal file
12
spine-ts/spine-threejs/example/typescript/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<title>Pixi Typescript Example</title>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
</head>
|
||||
<body>
|
||||
<script src='build/index.js'></script>
|
||||
</body>
|
||||
</html>
|
||||
135
spine-ts/spine-threejs/example/typescript/index.ts
Normal file
135
spine-ts/spine-threejs/example/typescript/index.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import * as THREE from "three";
|
||||
import * as spine from "@esotericsoftware/spine-threejs";
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||
|
||||
let scene: THREE.Scene;
|
||||
let camera: THREE.PerspectiveCamera;
|
||||
let renderer: THREE.WebGLRenderer;
|
||||
let geometry, material, mesh, skeletonMesh: spine.SkeletonMesh;
|
||||
let atlas;
|
||||
let atlasLoader;
|
||||
let assetManager: spine.AssetManager;
|
||||
let canvas: HTMLCanvasElement;
|
||||
let controls: OrbitControls;
|
||||
let lastFrameTime = Date.now() / 1000;
|
||||
|
||||
let baseUrl = "assets/";
|
||||
let skeletonFile = "raptor-pro.json";
|
||||
let atlasFile = skeletonFile
|
||||
.replace("-pro", "")
|
||||
.replace("-ess", "")
|
||||
.replace(".json", ".atlas");
|
||||
let animation = "walk";
|
||||
|
||||
function init() {
|
||||
// create the THREE.JS camera, scene and renderer (WebGL)
|
||||
let width = window.innerWidth,
|
||||
height = window.innerHeight;
|
||||
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||
camera.position.y = 100;
|
||||
camera.position.z = 400;
|
||||
scene = new THREE.Scene();
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(width, height);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
canvas = renderer.domElement;
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
|
||||
// LIGHTS - Ambient
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 7.0)
|
||||
scene.add(ambientLight)
|
||||
|
||||
// LIGHTS - spotLight
|
||||
const spotLight = new THREE.SpotLight(0xffffff, 5, 1200, Math.PI / 4, 0, 0)
|
||||
spotLight.position.set(0, 1000, 0)
|
||||
spotLight.castShadow = true
|
||||
spotLight.shadow.mapSize.set(8192, 8192)
|
||||
spotLight.shadow.bias = -0.00001;
|
||||
scene.add(spotLight)
|
||||
|
||||
// load the assets required to display the Raptor model
|
||||
assetManager = new spine.AssetManager(baseUrl);
|
||||
assetManager.loadText(skeletonFile);
|
||||
assetManager.loadTextureAtlas(atlasFile);
|
||||
|
||||
requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (assetManager.isLoadingComplete()) {
|
||||
// Add a box to the scene to which we attach the skeleton mesh
|
||||
geometry = new THREE.BoxGeometry(200, 200, 200);
|
||||
material = new THREE.MeshBasicMaterial({
|
||||
color: 0xff0000,
|
||||
wireframe: true,
|
||||
});
|
||||
mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
|
||||
// Load the texture atlas using name.atlas and name.png from the AssetManager.
|
||||
// The function passed to TextureAtlas is used to resolve relative paths.
|
||||
atlas = assetManager.require(atlasFile);
|
||||
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
|
||||
// Create a SkeletonJson instance for parsing the .json file.
|
||||
let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonJson.scale = 0.4;
|
||||
let skeletonData = skeletonJson.readSkeletonData(
|
||||
assetManager.require(skeletonFile)
|
||||
);
|
||||
|
||||
// Create a SkeletonMesh from the data and attach it to the scene
|
||||
skeletonMesh = new spine.SkeletonMesh({
|
||||
skeletonData,
|
||||
materialFactory(parameters) {
|
||||
return new THREE.MeshStandardMaterial({ ...parameters, metalness: .5 });
|
||||
},
|
||||
});
|
||||
skeletonMesh.state.setAnimation(0, animation, true);
|
||||
mesh.add(skeletonMesh);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
} else requestAnimationFrame(load);
|
||||
}
|
||||
|
||||
let lastTime = Date.now();
|
||||
function render() {
|
||||
// calculate delta time for animation purposes
|
||||
let now = Date.now() / 1000;
|
||||
let delta = now - lastFrameTime;
|
||||
lastFrameTime = now;
|
||||
|
||||
// resize canvas to use full page, adjust camera/renderer
|
||||
resize();
|
||||
|
||||
// Update orbital controls
|
||||
controls.update();
|
||||
|
||||
// update the animation
|
||||
skeletonMesh.update(delta);
|
||||
|
||||
// render the scene
|
||||
renderer.render(scene, camera);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
let w = window.innerWidth;
|
||||
let h = window.innerHeight;
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize(w, h);
|
||||
}
|
||||
|
||||
init();
|
||||
3168
spine-ts/spine-threejs/example/typescript/package-lock.json
generated
Normal file
3168
spine-ts/spine-threejs/example/typescript/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
spine-ts/spine-threejs/example/typescript/package.json
Normal file
20
spine-ts/spine-threejs/example/typescript/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "spine-threejs-ts-example",
|
||||
"description": "Spine threejs ts example",
|
||||
"author": "Esoteric Software LLC",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build":"npx esbuild index.ts --bundle --sourcemap --outfile=build/index.js",
|
||||
"dev": "npx concurrently \"npx live-server --no-browser\" \"npm run build -- --watch\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-threejs": "4.2.67",
|
||||
"three": "0.162.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "0.17.17",
|
||||
"concurrently": "^7.6.0",
|
||||
"live-server": "^1.2.2"
|
||||
}
|
||||
}
|
||||
@ -32,5 +32,11 @@
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.66"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "0.162.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": "0.162.0"
|
||||
}
|
||||
}
|
||||
@ -27,13 +27,18 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { SkeletonMeshMaterial, SkeletonMeshMaterialParametersCustomizer } from "./SkeletonMesh.js";
|
||||
import * as THREE from "three"
|
||||
|
||||
import { ThreeJsTexture, ThreeBlendOptions } from "./ThreeJsTexture.js";
|
||||
import { BlendMode } from "@esotericsoftware/spine-core";
|
||||
import { SkeletonMesh } from "./SkeletonMesh.js";
|
||||
|
||||
export type MaterialWithMap = THREE.Material & { map: THREE.Texture | null };
|
||||
export class MeshBatcher extends THREE.Mesh {
|
||||
private static VERTEX_SIZE = 9;
|
||||
public static MAX_VERTICES = 10920;
|
||||
|
||||
// private static VERTEX_SIZE = 9;
|
||||
private vertexSize = 9;
|
||||
private vertexBuffer: THREE.InterleavedBuffer;
|
||||
private vertices: Float32Array;
|
||||
private verticesLength = 0;
|
||||
@ -41,23 +46,36 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
private indicesLength = 0;
|
||||
private materialGroups: [number, number, number][] = [];
|
||||
|
||||
constructor (maxVertices: number = 10920, private materialCustomizer: SkeletonMeshMaterialParametersCustomizer = (parameters) => { }) {
|
||||
constructor (
|
||||
maxVertices: number = MeshBatcher.MAX_VERTICES,
|
||||
private materialFactory: (parameters: THREE.MaterialParameters) => MaterialWithMap,
|
||||
private twoColorTint = true,
|
||||
) {
|
||||
super();
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
let vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
|
||||
|
||||
if (maxVertices > MeshBatcher.MAX_VERTICES) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
|
||||
if (twoColorTint) {
|
||||
this.vertexSize += 3;
|
||||
}
|
||||
|
||||
let vertices = this.vertices = new Float32Array(maxVertices * this.vertexSize);
|
||||
let indices = this.indices = new Uint16Array(maxVertices * 3);
|
||||
let geo = new THREE.BufferGeometry();
|
||||
let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
|
||||
let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, this.vertexSize);
|
||||
vertexBuffer.usage = WebGLRenderingContext.DYNAMIC_DRAW;
|
||||
geo.setAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false));
|
||||
geo.setAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false));
|
||||
geo.setAttribute("uv", new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 7, false));
|
||||
if (twoColorTint) {
|
||||
geo.setAttribute("darkcolor", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 9, false));
|
||||
}
|
||||
geo.setIndex(new THREE.BufferAttribute(indices, 1));
|
||||
geo.getIndex()!.usage = WebGLRenderingContext.DYNAMIC_DRAW;
|
||||
geo.drawRange.start = 0;
|
||||
geo.drawRange.count = 0;
|
||||
this.geometry = geo;
|
||||
this.material = [new SkeletonMeshMaterial(materialCustomizer)];
|
||||
this.material = [];
|
||||
}
|
||||
|
||||
dispose () {
|
||||
@ -80,13 +98,13 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
geo.clearGroups();
|
||||
this.materialGroups = [];
|
||||
if (this.material instanceof THREE.Material) {
|
||||
const meshMaterial = this.material as SkeletonMeshMaterial;
|
||||
meshMaterial.uniforms.map.value = null;
|
||||
const meshMaterial = this.material as MaterialWithMap;
|
||||
meshMaterial.map = null;
|
||||
meshMaterial.blending = THREE.NormalBlending;
|
||||
} else if (Array.isArray(this.material)) {
|
||||
for (let i = 0; i < this.material.length; i++) {
|
||||
const meshMaterial = this.material[i] as SkeletonMeshMaterial;
|
||||
meshMaterial.uniforms.map.value = null;
|
||||
const meshMaterial = this.material[i] as MaterialWithMap;
|
||||
meshMaterial.map = null;
|
||||
meshMaterial.blending = THREE.NormalBlending;
|
||||
}
|
||||
}
|
||||
@ -100,25 +118,48 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
|
||||
canBatch (numVertices: number, numIndices: number) {
|
||||
if (this.indicesLength + numIndices >= this.indices.byteLength / 2) return false;
|
||||
if (this.verticesLength / MeshBatcher.VERTEX_SIZE + numVertices >= (this.vertices.byteLength / 4) / MeshBatcher.VERTEX_SIZE) return false;
|
||||
if (this.verticesLength / this.vertexSize + numVertices >= (this.vertices.byteLength / 4) / this.vertexSize) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
batch (vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z: number = 0) {
|
||||
let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
|
||||
let indexStart = this.verticesLength / this.vertexSize;
|
||||
let vertexBuffer = this.vertices;
|
||||
let i = this.verticesLength;
|
||||
let j = 0;
|
||||
for (; j < verticesLength;) {
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = z;
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
vertexBuffer[i++] = vertices[j++];
|
||||
if (this.twoColorTint) {
|
||||
for (; j < verticesLength;) {
|
||||
vertexBuffer[i++] = vertices[j++]; // x
|
||||
vertexBuffer[i++] = vertices[j++]; // y
|
||||
vertexBuffer[i++] = z; // z
|
||||
|
||||
vertexBuffer[i++] = vertices[j++]; // r
|
||||
vertexBuffer[i++] = vertices[j++]; // g
|
||||
vertexBuffer[i++] = vertices[j++]; // b
|
||||
vertexBuffer[i++] = vertices[j++]; // a
|
||||
|
||||
vertexBuffer[i++] = vertices[j++]; // u
|
||||
vertexBuffer[i++] = vertices[j++]; // v
|
||||
|
||||
vertexBuffer[i++] = vertices[j++]; // dark r
|
||||
vertexBuffer[i++] = vertices[j++]; // dark g
|
||||
vertexBuffer[i++] = vertices[j++]; // dark b
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
for (; j < verticesLength;) {
|
||||
vertexBuffer[i++] = vertices[j++]; // x
|
||||
vertexBuffer[i++] = vertices[j++]; // y
|
||||
vertexBuffer[i++] = z; // z
|
||||
|
||||
vertexBuffer[i++] = vertices[j++]; // r
|
||||
vertexBuffer[i++] = vertices[j++]; // g
|
||||
vertexBuffer[i++] = vertices[j++]; // b
|
||||
vertexBuffer[i++] = vertices[j++]; // a
|
||||
|
||||
vertexBuffer[i++] = vertices[j++]; // u
|
||||
vertexBuffer[i++] = vertices[j++]; // v
|
||||
}
|
||||
}
|
||||
this.verticesLength = i;
|
||||
|
||||
@ -130,17 +171,16 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
|
||||
end () {
|
||||
this.vertexBuffer.needsUpdate = this.verticesLength > 0;
|
||||
this.vertexBuffer.updateRange.offset = 0;
|
||||
this.vertexBuffer.updateRange.count = this.verticesLength;
|
||||
this.vertexBuffer.addUpdateRange(0, this.verticesLength);
|
||||
let geo = (<THREE.BufferGeometry>this.geometry);
|
||||
this.closeMaterialGroups();
|
||||
let index = geo.getIndex();
|
||||
if (!index) throw new Error("BufferAttribute must not be null.");
|
||||
index.needsUpdate = this.indicesLength > 0;
|
||||
index.updateRange.offset = 0;
|
||||
index.updateRange.count = this.indicesLength;
|
||||
index.addUpdateRange(0, this.indicesLength);
|
||||
geo.drawRange.start = 0;
|
||||
geo.drawRange.count = this.indicesLength;
|
||||
geo.computeVertexNormals();
|
||||
}
|
||||
|
||||
addMaterialGroup (indicesLength: number, materialGroup: number) {
|
||||
@ -168,14 +208,14 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
|
||||
if (Array.isArray(this.material)) {
|
||||
for (let i = 0; i < this.material.length; i++) {
|
||||
const meshMaterial = this.material[i] as SkeletonMeshMaterial;
|
||||
const meshMaterial = this.material[i] as MaterialWithMap;
|
||||
|
||||
if (!meshMaterial.uniforms.map.value) {
|
||||
if (!meshMaterial.map) {
|
||||
updateMeshMaterial(meshMaterial, slotTexture, blendingObject);
|
||||
return i;
|
||||
}
|
||||
|
||||
if (meshMaterial.uniforms.map.value === slotTexture
|
||||
if (meshMaterial.map === slotTexture
|
||||
&& blendingObject.blending === meshMaterial.blending
|
||||
&& (blendingObject.blendSrc === undefined || blendingObject.blendSrc === meshMaterial.blendSrc)
|
||||
&& (blendingObject.blendDst === undefined || blendingObject.blendDst === meshMaterial.blendDst)
|
||||
@ -186,8 +226,8 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
}
|
||||
}
|
||||
|
||||
const meshMaterial = new SkeletonMeshMaterial(this.materialCustomizer);
|
||||
updateMeshMaterial(meshMaterial, slotTexture, blendingObject);
|
||||
const meshMaterial = this.newMaterial();
|
||||
updateMeshMaterial(meshMaterial as MaterialWithMap, slotTexture, blendingObject);
|
||||
this.material.push(meshMaterial);
|
||||
group = this.material.length - 1;
|
||||
} else {
|
||||
@ -196,10 +236,162 @@ export class MeshBatcher extends THREE.Mesh {
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private newMaterial (): MaterialWithMap {
|
||||
const meshMaterial = this.materialFactory(SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS);
|
||||
|
||||
if (!('map' in meshMaterial)) {
|
||||
throw new Error("The material factory must return a material having the map property for the texture.");
|
||||
}
|
||||
|
||||
if (meshMaterial instanceof SkeletonMeshMaterial) {
|
||||
return meshMaterial;
|
||||
}
|
||||
|
||||
if (this.twoColorTint) {
|
||||
meshMaterial.defines = {
|
||||
...meshMaterial.defines,
|
||||
USE_SPINE_DARK_TINT: 1,
|
||||
}
|
||||
}
|
||||
|
||||
meshMaterial.onBeforeCompile = spineOnBeforeCompile;
|
||||
|
||||
return meshMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
function updateMeshMaterial (meshMaterial: SkeletonMeshMaterial, slotTexture: THREE.Texture, blending: ThreeBlendOptions) {
|
||||
meshMaterial.uniforms.map.value = slotTexture;
|
||||
const spineOnBeforeCompile = (shader: THREE.WebGLProgramParametersWithUniforms) => {
|
||||
|
||||
let code;
|
||||
|
||||
// VERTEX SHADER MODIFICATIONS
|
||||
|
||||
// Add dark color attribute
|
||||
shader.vertexShader = `
|
||||
#if defined( USE_SPINE_DARK_TINT )
|
||||
attribute vec3 darkcolor;
|
||||
#endif
|
||||
` + shader.vertexShader;
|
||||
|
||||
// Add dark color attribute
|
||||
code = `
|
||||
#if defined( USE_SPINE_DARK_TINT )
|
||||
varying vec3 v_dark;
|
||||
#endif
|
||||
`;
|
||||
shader.vertexShader = insertAfterElementInShader(shader.vertexShader, '#include <color_pars_vertex>', code);
|
||||
|
||||
// Define v_dark varying
|
||||
code = `
|
||||
#if defined( USE_SPINE_DARK_TINT )
|
||||
v_dark = vec3( 1.0 );
|
||||
v_dark *= darkcolor;
|
||||
#endif
|
||||
`;
|
||||
shader.vertexShader = insertAfterElementInShader(shader.vertexShader, '#include <color_vertex>', code);
|
||||
|
||||
|
||||
// FRAGMENT SHADER MODIFICATIONS
|
||||
|
||||
// Define v_dark varying
|
||||
code = `
|
||||
#ifdef USE_SPINE_DARK_TINT
|
||||
varying vec3 v_dark;
|
||||
#endif
|
||||
`;
|
||||
shader.fragmentShader = insertAfterElementInShader(shader.fragmentShader, '#include <color_pars_fragment>', code);
|
||||
|
||||
// Replacing color_fragment with the addition of dark tint formula if twoColorTint is true
|
||||
shader.fragmentShader = shader.fragmentShader.replace(
|
||||
'#include <color_fragment>',
|
||||
`
|
||||
#ifdef USE_SPINE_DARK_TINT
|
||||
#ifdef USE_COLOR_ALPHA
|
||||
diffuseColor.a *= vColor.a;
|
||||
diffuseColor.rgb *= (1.0 - diffuseColor.rgb) * v_dark.rgb + diffuseColor.rgb * vColor.rgb;
|
||||
#endif
|
||||
#else
|
||||
#ifdef USE_COLOR_ALPHA
|
||||
diffuseColor *= vColor;
|
||||
#endif
|
||||
#endif
|
||||
`
|
||||
);
|
||||
|
||||
// We had to remove this because we need premultiplied blending modes, but our textures are already premultiplied
|
||||
// We could actually create a custom blending mode for Normal and Additive too
|
||||
shader.fragmentShader = shader.fragmentShader.replace('#include <premultiplied_alpha_fragment>', '');
|
||||
|
||||
// We had to remove this (and don't assign a color space to the texture) otherwise we would see artifacts on texture edges
|
||||
shader.fragmentShader = shader.fragmentShader.replace('#include <colorspace_fragment>', '');
|
||||
|
||||
}
|
||||
|
||||
function insertAfterElementInShader (shader: string, elementToFind: string, codeToInsert: string) {
|
||||
const index = shader.indexOf(elementToFind);
|
||||
const beforeToken = shader.slice(0, index + elementToFind.length);
|
||||
const afterToken = shader.slice(index + elementToFind.length);
|
||||
return beforeToken + codeToInsert + afterToken;
|
||||
}
|
||||
|
||||
function updateMeshMaterial (meshMaterial: MaterialWithMap, slotTexture: THREE.Texture, blending: ThreeBlendOptions) {
|
||||
meshMaterial.map = slotTexture;
|
||||
Object.assign(meshMaterial, blending);
|
||||
meshMaterial.needsUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
|
||||
|
||||
public get map (): THREE.Texture | null {
|
||||
return this.uniforms.map.value;
|
||||
}
|
||||
|
||||
public set map (value: THREE.Texture | null) {
|
||||
this.uniforms.map.value = value;
|
||||
}
|
||||
|
||||
constructor (parameters: THREE.ShaderMaterialParameters) {
|
||||
|
||||
let vertexShader = `
|
||||
varying vec2 vUv;
|
||||
varying vec4 vColor;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
vColor = color;
|
||||
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
|
||||
}
|
||||
`;
|
||||
let fragmentShader = `
|
||||
uniform sampler2D map;
|
||||
#ifdef USE_SPINE_ALPHATEST
|
||||
uniform float alphaTest;
|
||||
#endif
|
||||
varying vec2 vUv;
|
||||
varying vec4 vColor;
|
||||
void main(void) {
|
||||
gl_FragColor = texture2D(map, vUv)*vColor;
|
||||
#ifdef USE_SPINE_ALPHATEST
|
||||
if (gl_FragColor.a < alphaTest) discard;
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
|
||||
let uniforms = { map: { value: null } };
|
||||
if (parameters.uniforms) {
|
||||
uniforms = { ...parameters.uniforms, ...uniforms };
|
||||
}
|
||||
|
||||
if (parameters.alphaTest && parameters.alphaTest > 0) {
|
||||
parameters.defines = { USE_SPINE_ALPHATEST: 1 };
|
||||
}
|
||||
|
||||
super({
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
...parameters,
|
||||
uniforms,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -27,10 +27,10 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
AnimationState,
|
||||
AnimationStateData,
|
||||
BlendMode,
|
||||
ClippingAttachment,
|
||||
Color,
|
||||
MeshAttachment,
|
||||
@ -40,69 +40,51 @@ import {
|
||||
Skeleton,
|
||||
SkeletonClipping,
|
||||
SkeletonData,
|
||||
TextureAtlasRegion,
|
||||
SkeletonBinary,
|
||||
SkeletonJson,
|
||||
Utils,
|
||||
Vector2,
|
||||
} from "@esotericsoftware/spine-core";
|
||||
import { MeshBatcher } from "./MeshBatcher.js";
|
||||
import * as THREE from "three";
|
||||
|
||||
import { MaterialWithMap, MeshBatcher } from "./MeshBatcher.js";
|
||||
import { ThreeJsTexture } from "./ThreeJsTexture.js";
|
||||
|
||||
export type SkeletonMeshMaterialParametersCustomizer = (
|
||||
materialParameters: THREE.ShaderMaterialParameters
|
||||
) => void;
|
||||
type SkeletonMeshMaterialParametersCustomizer = (materialParameters: THREE.MaterialParameters) => void;
|
||||
type SkeletonMeshConfiguration = {
|
||||
|
||||
export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
|
||||
constructor (customizer: SkeletonMeshMaterialParametersCustomizer) {
|
||||
let vertexShader = `
|
||||
attribute vec4 color;
|
||||
varying vec2 vUv;
|
||||
varying vec4 vColor;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
vColor = color;
|
||||
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
|
||||
}
|
||||
`;
|
||||
let fragmentShader = `
|
||||
uniform sampler2D map;
|
||||
#ifdef USE_SPINE_ALPHATEST
|
||||
uniform float alphaTest;
|
||||
#endif
|
||||
varying vec2 vUv;
|
||||
varying vec4 vColor;
|
||||
void main(void) {
|
||||
gl_FragColor = texture2D(map, vUv)*vColor;
|
||||
#ifdef USE_SPINE_ALPHATEST
|
||||
if (gl_FragColor.a < alphaTest) discard;
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
/** The skeleton data object loaded by using {@link SkeletonJson} or {@link SkeletonBinary} */
|
||||
skeletonData: SkeletonData,
|
||||
|
||||
let parameters: THREE.ShaderMaterialParameters = {
|
||||
uniforms: {
|
||||
map: { value: null },
|
||||
},
|
||||
vertexShader: vertexShader,
|
||||
fragmentShader: fragmentShader,
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
depthWrite: true,
|
||||
alphaTest: 0.0,
|
||||
};
|
||||
customizer(parameters);
|
||||
if (parameters.alphaTest && parameters.alphaTest > 0) {
|
||||
parameters.defines = { USE_SPINE_ALPHATEST: 1 };
|
||||
if (!parameters.uniforms) parameters.uniforms = {};
|
||||
parameters.uniforms["alphaTest"] = { value: parameters.alphaTest };
|
||||
}
|
||||
super(parameters);
|
||||
// non-pma textures are premultiply on upload, so we set premultipliedAlpha to true
|
||||
this.premultipliedAlpha = true;
|
||||
}
|
||||
}
|
||||
/** Set it to true to enable tint black rendering */
|
||||
twoColorTint?: boolean,
|
||||
|
||||
/**
|
||||
* The function used to create the materials for the meshes composing this Object3D.
|
||||
* The material used must have the `map` property.
|
||||
* By default a MeshStandardMaterial is used, so no light and shadows are available.
|
||||
* Use a MeshStandardMaterial
|
||||
*
|
||||
* @param parameters The default parameters with which this function is invoked.
|
||||
* You should pass this parameters, once personalized, to the costructor of the material you want to use.
|
||||
* Default values are defined in {@link SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS}.
|
||||
*
|
||||
* @returns An instance of the material you want to be used for the meshes of this Object3D. The material must have the `map` property.
|
||||
*/
|
||||
materialFactory?: (parameters: THREE.MaterialParameters) => MaterialWithMap,
|
||||
};
|
||||
|
||||
export class SkeletonMesh extends THREE.Object3D {
|
||||
// public static readonly DEFAULT_MATERIAL_PARAMETERS: THREE.MaterialParameters = {
|
||||
public static readonly DEFAULT_MATERIAL_PARAMETERS: THREE.MaterialParameters = {
|
||||
side: THREE.DoubleSide,
|
||||
depthWrite: true,
|
||||
depthTest: true,
|
||||
transparent: true,
|
||||
alphaTest: 0.001,
|
||||
vertexColors: true,
|
||||
premultipliedAlpha: true,
|
||||
}
|
||||
|
||||
tempPos: Vector2 = new Vector2();
|
||||
tempUv: Vector2 = new Vector2();
|
||||
tempLight = new Color();
|
||||
@ -112,26 +94,87 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
zOffset: number = 0.1;
|
||||
|
||||
private batches = new Array<MeshBatcher>();
|
||||
private materialFactory: (parameters: THREE.MaterialParameters) => MaterialWithMap;
|
||||
private nextBatchIndex = 0;
|
||||
private clipper: SkeletonClipping = new SkeletonClipping();
|
||||
|
||||
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||
static VERTEX_SIZE = 2 + 2 + 4;
|
||||
private vertexSize = 2 + 2 + 4;
|
||||
private twoColorTint;
|
||||
|
||||
private vertices = Utils.newFloatArray(1024);
|
||||
private tempColor = new Color();
|
||||
private tempDarkColor = new Color();
|
||||
|
||||
private _castShadow = false;
|
||||
private _receiveShadow = false;
|
||||
|
||||
/**
|
||||
* Create an Object3D containing meshes representing your Spine animation.
|
||||
* Personalize your material providing a {@link SkeletonMeshConfiguration}
|
||||
* @param skeletonData
|
||||
*/
|
||||
constructor (configuration: SkeletonMeshConfiguration)
|
||||
/**
|
||||
* @deprecated This signature is deprecated, please use the one with a single {@link SkeletonMeshConfiguration} parameter
|
||||
*/
|
||||
constructor (
|
||||
skeletonData: SkeletonData,
|
||||
private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = (
|
||||
material
|
||||
) => { }
|
||||
materialCustomizer: SkeletonMeshMaterialParametersCustomizer,
|
||||
)
|
||||
constructor (
|
||||
skeletonDataOrConfiguration: SkeletonData | SkeletonMeshConfiguration,
|
||||
materialCustomizer: SkeletonMeshMaterialParametersCustomizer = () => { }
|
||||
) {
|
||||
super();
|
||||
|
||||
this.skeleton = new Skeleton(skeletonData);
|
||||
let animData = new AnimationStateData(skeletonData);
|
||||
if (!('skeletonData' in skeletonDataOrConfiguration)) {
|
||||
const materialFactory = () => {
|
||||
const parameters: THREE.MaterialParameters = { ...SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS };
|
||||
materialCustomizer(parameters);
|
||||
return new THREE.MeshBasicMaterial(parameters);
|
||||
};
|
||||
skeletonDataOrConfiguration = {
|
||||
skeletonData: skeletonDataOrConfiguration,
|
||||
materialFactory,
|
||||
}
|
||||
}
|
||||
|
||||
this.twoColorTint = skeletonDataOrConfiguration.twoColorTint ?? true;
|
||||
if (this.twoColorTint) {
|
||||
this.vertexSize += 4;
|
||||
}
|
||||
|
||||
this.materialFactory = skeletonDataOrConfiguration.materialFactory ?? (() => new THREE.MeshBasicMaterial(SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS));
|
||||
this.skeleton = new Skeleton(skeletonDataOrConfiguration.skeletonData);
|
||||
let animData = new AnimationStateData(skeletonDataOrConfiguration.skeletonData);
|
||||
this.state = new AnimationState(animData);
|
||||
|
||||
Object.defineProperty(this, 'castShadow', {
|
||||
get: () => this._castShadow,
|
||||
set: (value: boolean) => {
|
||||
this._castShadow = value;
|
||||
this.traverse((child) => {
|
||||
if (child instanceof MeshBatcher) {
|
||||
child.castShadow = value;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'receiveShadow', {
|
||||
get: () => this._receiveShadow,
|
||||
set: (value: boolean) => {
|
||||
this._receiveShadow = value;
|
||||
// Propagate to children
|
||||
this.traverse((child) => {
|
||||
if (child instanceof MeshBatcher) {
|
||||
child.receiveShadow = value;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
update (deltaTime: number) {
|
||||
@ -162,7 +205,9 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
|
||||
private nextBatch () {
|
||||
if (this.batches.length == this.nextBatchIndex) {
|
||||
let batch = new MeshBatcher(10920, this.materialCustomerizer);
|
||||
let batch = new MeshBatcher(MeshBatcher.MAX_VERTICES, this.materialFactory, this.twoColorTint);
|
||||
batch.castShadow = this._castShadow;
|
||||
batch.receiveShadow = this._receiveShadow;
|
||||
this.add(batch);
|
||||
this.batches.push(batch);
|
||||
}
|
||||
@ -174,8 +219,6 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
private updateGeometry () {
|
||||
this.clearBatches();
|
||||
|
||||
let tempPos = this.tempPos;
|
||||
let tempUv = this.tempUv;
|
||||
let tempLight = this.tempLight;
|
||||
let tempDark = this.tempDark;
|
||||
let clipper = this.clipper;
|
||||
@ -189,7 +232,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
let z = 0;
|
||||
let zOffset = this.zOffset;
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
let vertexSize = clipper.isClipping() ? 2 : SkeletonMesh.VERTEX_SIZE;
|
||||
let vertexSize = clipper.isClipping() ? 2 : this.vertexSize;
|
||||
let slot = drawOrder[i];
|
||||
if (!slot.bone.active) {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
@ -249,6 +292,16 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
alpha
|
||||
);
|
||||
|
||||
let darkColor = this.tempDarkColor;
|
||||
if (!slot.darkColor)
|
||||
darkColor.set(1, 1, 1, 0);
|
||||
else {
|
||||
darkColor.r = slot.darkColor.r * alpha;
|
||||
darkColor.g = slot.darkColor.g * alpha;
|
||||
darkColor.b = slot.darkColor.b * alpha;
|
||||
darkColor.a = 1;
|
||||
}
|
||||
|
||||
let finalVertices: NumberArrayLike;
|
||||
let finalVerticesLength: number;
|
||||
let finalIndices: NumberArrayLike;
|
||||
@ -262,7 +315,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
uvs,
|
||||
color,
|
||||
tempLight,
|
||||
false
|
||||
this.twoColorTint,
|
||||
);
|
||||
let clippedVertices = clipper.clippedVertices;
|
||||
let clippedTriangles = clipper.clippedTriangles;
|
||||
@ -272,18 +325,30 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
finalIndicesLength = clippedTriangles.length;
|
||||
} else {
|
||||
let verts = vertices;
|
||||
for (
|
||||
let v = 2, u = 0, n = numFloats;
|
||||
v < n;
|
||||
v += vertexSize, u += 2
|
||||
) {
|
||||
verts[v] = color.r;
|
||||
verts[v + 1] = color.g;
|
||||
verts[v + 2] = color.b;
|
||||
verts[v + 3] = color.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
if (!this.twoColorTint) {
|
||||
for (let v = 2, u = 0, n = numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = color.r;
|
||||
verts[v + 1] = color.g;
|
||||
verts[v + 2] = color.b;
|
||||
verts[v + 3] = color.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
}
|
||||
} else {
|
||||
for (let v = 2, u = 0, n = numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = color.r;
|
||||
verts[v + 1] = color.g;
|
||||
verts[v + 2] = color.b;
|
||||
verts[v + 3] = color.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
verts[v + 6] = darkColor.r;
|
||||
verts[v + 7] = darkColor.g;
|
||||
verts[v + 8] = darkColor.b;
|
||||
verts[v + 9] = darkColor.a;
|
||||
}
|
||||
}
|
||||
|
||||
finalVertices = vertices;
|
||||
finalVerticesLength = numFloats;
|
||||
finalIndices = triangles;
|
||||
@ -298,7 +363,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
// Start new batch if this one can't hold vertices/indices
|
||||
if (
|
||||
!batch.canBatch(
|
||||
finalVerticesLength / SkeletonMesh.VERTEX_SIZE,
|
||||
finalVerticesLength / this.vertexSize,
|
||||
finalIndicesLength
|
||||
)
|
||||
) {
|
||||
|
||||
@ -42,12 +42,16 @@ export class ThreeJsTexture extends Texture {
|
||||
// if the texture is not pma, we ask to threejs to premultiply on upload
|
||||
this.texture.premultiplyAlpha = !pma;
|
||||
this.texture.flipY = false;
|
||||
|
||||
// Keep this as a reference - this is necessary in future versions of ThreeJS
|
||||
// this.texture.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
this.texture.needsUpdate = true;
|
||||
}
|
||||
|
||||
setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
|
||||
this.texture.minFilter = ThreeJsTexture.toThreeJsTextureFilter(minFilter);
|
||||
this.texture.magFilter = ThreeJsTexture.toThreeJsTextureFilter(magFilter);
|
||||
this.texture.minFilter = ThreeJsTexture.toThreeJsMinificationTextureFilter(minFilter);
|
||||
this.texture.magFilter = ThreeJsTexture.toThreeJsMagnificationTextureFilter(magFilter);
|
||||
}
|
||||
|
||||
setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
|
||||
@ -59,7 +63,7 @@ export class ThreeJsTexture extends Texture {
|
||||
this.texture.dispose();
|
||||
}
|
||||
|
||||
static toThreeJsTextureFilter (filter: TextureFilter) {
|
||||
static toThreeJsMinificationTextureFilter (filter: TextureFilter): THREE.MinificationTextureFilter {
|
||||
if (filter === TextureFilter.Linear) return THREE.LinearFilter;
|
||||
else if (filter === TextureFilter.MipMap) return THREE.LinearMipMapLinearFilter; // also includes TextureFilter.MipMapLinearLinear
|
||||
else if (filter === TextureFilter.MipMapLinearNearest) return THREE.LinearMipMapNearestFilter;
|
||||
@ -69,6 +73,16 @@ export class ThreeJsTexture extends Texture {
|
||||
else throw new Error("Unknown texture filter: " + filter);
|
||||
}
|
||||
|
||||
static toThreeJsMagnificationTextureFilter (filter: TextureFilter): THREE.MagnificationTextureFilter {
|
||||
if (filter === TextureFilter.Linear) return THREE.LinearFilter;
|
||||
else if (filter === TextureFilter.MipMap) return THREE.LinearFilter;
|
||||
else if (filter === TextureFilter.MipMapLinearNearest) return THREE.NearestFilter;
|
||||
else if (filter === TextureFilter.MipMapNearestLinear) return THREE.LinearFilter;
|
||||
else if (filter === TextureFilter.MipMapNearestNearest) return THREE.NearestFilter;
|
||||
else if (filter === TextureFilter.Nearest) return THREE.NearestFilter;
|
||||
else throw new Error("Unknown texture filter: " + filter);
|
||||
}
|
||||
|
||||
static toThreeJsTextureWrap (wrap: TextureWrap) {
|
||||
if (wrap === TextureWrap.ClampToEdge) return THREE.ClampToEdgeWrapping;
|
||||
else if (wrap === TextureWrap.MirroredRepeat) return THREE.MirroredRepeatWrapping;
|
||||
@ -76,9 +90,11 @@ export class ThreeJsTexture extends Texture {
|
||||
else throw new Error("Unknown texture wrap: " + wrap);
|
||||
}
|
||||
|
||||
static fist = true;
|
||||
static toThreeJsBlending (blend: BlendMode): ThreeBlendOptions {
|
||||
if (blend === BlendMode.Normal) return { blending: THREE.NormalBlending };
|
||||
else if (blend === BlendMode.Additive) return { blending: THREE.AdditiveBlending };
|
||||
// else if (blend === BlendMode.Multiply) return { blending: THREE.NormalBlending };
|
||||
else if (blend === BlendMode.Multiply) return {
|
||||
blending: THREE.CustomBlending,
|
||||
blendSrc: THREE.DstColorFactor,
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
declare global {
|
||||
var require: any;
|
||||
var THREE: any;
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.THREE) {
|
||||
|
||||
@ -11,11 +11,11 @@
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"src/OrbitControls.js"
|
||||
"**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"dist/**/*.d.ts"
|
||||
"dist/**/*.d.ts",
|
||||
"example/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user