[ts][threejs] Add support for lighting and shadow. Upgraded three to 0.162.0. Added new constructor.

This commit is contained in:
Davide Tantillo 2024-12-03 10:11:05 +01:00
parent 20827bf371
commit 7594c959dc
35 changed files with 24015 additions and 1748 deletions

View File

@ -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/"*

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

View 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 }
]
}
}
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

File diff suppressed because it is too large Load Diff

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

View File

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

View File

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

View File

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

View File

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

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

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

File diff suppressed because one or more lines are too long

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

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

View 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();

File diff suppressed because it is too large Load Diff

View 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"
}
}

View File

@ -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"
}
}

View File

@ -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,
});
}
}

View File

@ -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
)
) {

View File

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

View File

@ -29,6 +29,7 @@
declare global {
var require: any;
var THREE: any;
}
if (typeof window !== 'undefined' && window.THREE) {

View File

@ -11,11 +11,11 @@
}
},
"include": [
"**/*.ts",
"src/OrbitControls.js"
"**/*.ts"
],
"exclude": [
"dist/**/*.d.ts"
"dist/**/*.d.ts",
"example/**/*.ts"
],
"references": [
{