mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-05 02:06:53 +08:00
[ts] THREE.JS backend, revised batching using interleaved buffers, WIP
This commit is contained in:
parent
8536f210ce
commit
b9afff01fd
@ -11,7 +11,7 @@ module spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract setFilters (minFilter: TextureFilter, magFilter: TextureFilter): void;
|
abstract setFilters (minFilter: TextureFilter, magFilter: TextureFilter): void;
|
||||||
abstract setWraps (uWrap: TextureWrap, vWrap: TextureWrap): void;
|
abstract setWraps (uWrap: TextureWrap, vWrap: TextureWrap): void;
|
||||||
abstract dispose (): void;
|
abstract dispose (): void;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
279
spine-ts/threejs/example/assets/raptor.atlas
Normal file
279
spine-ts/threejs/example/assets/raptor.atlas
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
|
||||||
|
raptor.png
|
||||||
|
size: 1024,1024
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Linear,Linear
|
||||||
|
repeat: none
|
||||||
|
back_arm
|
||||||
|
rotate: true
|
||||||
|
xy: 140, 191
|
||||||
|
size: 46, 29
|
||||||
|
orig: 46, 29
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
back_bracer
|
||||||
|
rotate: true
|
||||||
|
xy: 167, 317
|
||||||
|
size: 39, 28
|
||||||
|
orig: 39, 28
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
back_hand
|
||||||
|
rotate: false
|
||||||
|
xy: 167, 358
|
||||||
|
size: 36, 34
|
||||||
|
orig: 36, 34
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
back_knee
|
||||||
|
rotate: false
|
||||||
|
xy: 299, 478
|
||||||
|
size: 49, 67
|
||||||
|
orig: 49, 67
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
back_thigh
|
||||||
|
rotate: true
|
||||||
|
xy: 167, 437
|
||||||
|
size: 39, 24
|
||||||
|
orig: 39, 24
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
eyes_closed
|
||||||
|
rotate: true
|
||||||
|
xy: 2, 2
|
||||||
|
size: 47, 45
|
||||||
|
orig: 47, 45
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
eyes_open
|
||||||
|
rotate: true
|
||||||
|
xy: 49, 2
|
||||||
|
size: 47, 45
|
||||||
|
orig: 47, 45
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
eyes_surprised
|
||||||
|
rotate: true
|
||||||
|
xy: 96, 2
|
||||||
|
size: 47, 45
|
||||||
|
orig: 47, 45
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
front_arm
|
||||||
|
rotate: false
|
||||||
|
xy: 419, 544
|
||||||
|
size: 48, 30
|
||||||
|
orig: 48, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
front_bracer
|
||||||
|
rotate: false
|
||||||
|
xy: 880, 695
|
||||||
|
size: 41, 29
|
||||||
|
orig: 41, 29
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
front_hand
|
||||||
|
rotate: true
|
||||||
|
xy: 167, 394
|
||||||
|
size: 41, 38
|
||||||
|
orig: 41, 38
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
front_open_hand
|
||||||
|
rotate: false
|
||||||
|
xy: 880, 726
|
||||||
|
size: 43, 44
|
||||||
|
orig: 43, 44
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
front_thigh
|
||||||
|
rotate: false
|
||||||
|
xy: 360, 545
|
||||||
|
size: 57, 29
|
||||||
|
orig: 57, 29
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
gun
|
||||||
|
rotate: false
|
||||||
|
xy: 785, 774
|
||||||
|
size: 107, 103
|
||||||
|
orig: 107, 103
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
gun_nohand
|
||||||
|
rotate: false
|
||||||
|
xy: 614, 703
|
||||||
|
size: 105, 102
|
||||||
|
orig: 105, 102
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
head
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 137
|
||||||
|
size: 136, 149
|
||||||
|
orig: 136, 149
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
lower_leg
|
||||||
|
rotate: true
|
||||||
|
xy: 780, 699
|
||||||
|
size: 73, 98
|
||||||
|
orig: 73, 98
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
mouth_grind
|
||||||
|
rotate: false
|
||||||
|
xy: 469, 544
|
||||||
|
size: 47, 30
|
||||||
|
orig: 47, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
mouth_oooo
|
||||||
|
rotate: true
|
||||||
|
xy: 894, 772
|
||||||
|
size: 105, 30
|
||||||
|
orig: 105, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
mouth_smile
|
||||||
|
rotate: true
|
||||||
|
xy: 140, 239
|
||||||
|
size: 47, 30
|
||||||
|
orig: 47, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
neck
|
||||||
|
rotate: true
|
||||||
|
xy: 538, 577
|
||||||
|
size: 18, 21
|
||||||
|
orig: 18, 21
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_arm_back
|
||||||
|
rotate: false
|
||||||
|
xy: 940, 936
|
||||||
|
size: 82, 86
|
||||||
|
orig: 82, 86
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_body
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 737
|
||||||
|
size: 610, 285
|
||||||
|
orig: 610, 285
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_front_arm
|
||||||
|
rotate: true
|
||||||
|
xy: 195, 464
|
||||||
|
size: 81, 102
|
||||||
|
orig: 81, 102
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_front_leg
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 478
|
||||||
|
size: 191, 257
|
||||||
|
orig: 191, 257
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_hindleg_back
|
||||||
|
rotate: false
|
||||||
|
xy: 614, 807
|
||||||
|
size: 169, 215
|
||||||
|
orig: 169, 215
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_horn
|
||||||
|
rotate: false
|
||||||
|
xy: 360, 655
|
||||||
|
size: 182, 80
|
||||||
|
orig: 182, 80
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_horn_back
|
||||||
|
rotate: false
|
||||||
|
xy: 360, 576
|
||||||
|
size: 176, 77
|
||||||
|
orig: 176, 77
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_jaw
|
||||||
|
rotate: false
|
||||||
|
xy: 785, 879
|
||||||
|
size: 153, 143
|
||||||
|
orig: 153, 143
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_saddle_noshadow
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 288
|
||||||
|
size: 163, 188
|
||||||
|
orig: 163, 188
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_saddle_strap_front
|
||||||
|
rotate: false
|
||||||
|
xy: 721, 710
|
||||||
|
size: 57, 95
|
||||||
|
orig: 57, 95
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_saddle_strap_rear
|
||||||
|
rotate: true
|
||||||
|
xy: 940, 880
|
||||||
|
size: 54, 74
|
||||||
|
orig: 54, 74
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_saddle_w_shadow
|
||||||
|
rotate: false
|
||||||
|
xy: 195, 547
|
||||||
|
size: 163, 188
|
||||||
|
orig: 163, 188
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
raptor_tongue
|
||||||
|
rotate: true
|
||||||
|
xy: 544, 649
|
||||||
|
size: 86, 64
|
||||||
|
orig: 86, 64
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
stirrup_back
|
||||||
|
rotate: true
|
||||||
|
xy: 140, 145
|
||||||
|
size: 44, 35
|
||||||
|
orig: 44, 35
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
stirrup_front
|
||||||
|
rotate: false
|
||||||
|
xy: 538, 597
|
||||||
|
size: 45, 50
|
||||||
|
orig: 45, 50
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
stirrup_strap
|
||||||
|
rotate: false
|
||||||
|
xy: 350, 497
|
||||||
|
size: 49, 46
|
||||||
|
orig: 49, 46
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
torso
|
||||||
|
rotate: true
|
||||||
|
xy: 610, 647
|
||||||
|
size: 54, 91
|
||||||
|
orig: 54, 91
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
visor
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 51
|
||||||
|
size: 131, 84
|
||||||
|
orig: 131, 84
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
2621
spine-ts/threejs/example/assets/raptor.json
Normal file
2621
spine-ts/threejs/example/assets/raptor.json
Normal file
File diff suppressed because one or more lines are too long
BIN
spine-ts/threejs/example/assets/raptor.png
Normal file
BIN
spine-ts/threejs/example/assets/raptor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 495 KiB |
102
spine-ts/threejs/example/index.html
Normal file
102
spine-ts/threejs/example/index.html
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>spine-threejs</title>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.js"></script>
|
||||||
|
<script src="../../build/spine-threejs.js"></script>
|
||||||
|
|
||||||
|
<style>body, input { font-family: tahoma; font-size: 11pt }</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var scene, camera, renderer;
|
||||||
|
var geometry, material, mesh, skeletonMesh;
|
||||||
|
var assetManager;
|
||||||
|
var lastFrameTime = Date.now();
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
|
||||||
|
var width = 640, height = 480;
|
||||||
|
camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
|
||||||
|
camera.position.z = 400;
|
||||||
|
|
||||||
|
geometry = new THREE.BoxGeometry(200, 200, 200);
|
||||||
|
material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });
|
||||||
|
|
||||||
|
mesh = new THREE.Mesh(geometry, material);
|
||||||
|
scene.add(mesh);
|
||||||
|
|
||||||
|
renderer = new THREE.WebGLRenderer();
|
||||||
|
renderer.setSize(width, height);
|
||||||
|
|
||||||
|
document.body.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
assetManager = new spine.threejs.AssetManager();
|
||||||
|
assetManager.loadText("assets/raptor.json");
|
||||||
|
assetManager.loadText("assets/raptor.atlas");
|
||||||
|
assetManager.loadTexture("assets/raptor.png");
|
||||||
|
|
||||||
|
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 = new spine.TextureAtlas(assetManager.get("assets/raptor.atlas"), function(path) {
|
||||||
|
return assetManager.get("assets/" + path);
|
||||||
|
});
|
||||||
|
|
||||||
|
var skeletonData = loadSkeleton("raptor", 0.4);
|
||||||
|
skeletonMesh = new spine.threejs.SkeletonMesh(skeletonData);
|
||||||
|
skeletonMesh.state.setAnimation(0, "walk", true);
|
||||||
|
mesh.add(skeletonMesh);
|
||||||
|
requestAnimationFrame(render);
|
||||||
|
} else requestAnimationFrame(load);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSkeleton (name, scale) {
|
||||||
|
// 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 = new spine.TextureAtlas(assetManager.get("assets/" + name + ".atlas"), function(path) {
|
||||||
|
return assetManager.get("assets/" + path);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a TextureAtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||||
|
atlasLoader = new spine.TextureAtlasAttachmentLoader(atlas);
|
||||||
|
|
||||||
|
// Create a SkeletonJson instance for parsing the .json file.
|
||||||
|
var skeletonJson = new spine.SkeletonJson(atlasLoader);
|
||||||
|
|
||||||
|
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||||
|
skeletonJson.scale = scale;
|
||||||
|
var skeletonData = skeletonJson.readSkeletonData(assetManager.get("assets/" + name + ".json"));
|
||||||
|
return skeletonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastTime = Date.now();
|
||||||
|
function render() {
|
||||||
|
var now = Date.now() / 1000;
|
||||||
|
var delta = now - lastFrameTime;
|
||||||
|
lastFrameTime = now;
|
||||||
|
|
||||||
|
var a = Math.sin(now);
|
||||||
|
var b = Math.cos(now);
|
||||||
|
|
||||||
|
mesh.rotation.x = a * Math.PI * 0.2;
|
||||||
|
mesh.rotation.y = b * Math.PI * 0.4;
|
||||||
|
|
||||||
|
skeletonMesh.update(delta);
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
|
||||||
|
requestAnimationFrame(render);
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
init();
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
spine-ts/threejs/src/AssetManager.ts
Normal file
9
spine-ts/threejs/src/AssetManager.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module spine.threejs {
|
||||||
|
export class AssetManager extends spine.AssetManager {
|
||||||
|
constructor () {
|
||||||
|
super((image: HTMLImageElement) => {
|
||||||
|
return new ThreeJsTexture(image);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
spine-ts/threejs/src/SkeletonMesh.ts
Normal file
51
spine-ts/threejs/src/SkeletonMesh.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module spine.threejs {
|
||||||
|
export class SkeletonMesh extends THREE.Mesh {
|
||||||
|
|
||||||
|
skeleton: Skeleton;
|
||||||
|
state: AnimationState;
|
||||||
|
|
||||||
|
private _vertexBuffer: THREE.InterleavedBuffer;
|
||||||
|
|
||||||
|
constructor (skeletonData: SkeletonData) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.skeleton = new Skeleton(skeletonData);
|
||||||
|
let animData = new AnimationStateData(skeletonData);
|
||||||
|
this.state = new AnimationState(animData);
|
||||||
|
|
||||||
|
this.material = new THREE.MeshBasicMaterial();
|
||||||
|
this.material.vertexColors = THREE.VertexColors;
|
||||||
|
|
||||||
|
let geometry: THREE.BufferGeometry = this.geometry = new THREE.BufferGeometry();
|
||||||
|
let vertexBuffer = this._vertexBuffer = new THREE.InterleavedBuffer(new Float32Array(8 * 3 * 10920), 8);
|
||||||
|
vertexBuffer.setDynamic(true);
|
||||||
|
geometry.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 0, false));
|
||||||
|
geometry.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 2, false));
|
||||||
|
geometry.addAttribute("uv", new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 6, false));
|
||||||
|
|
||||||
|
let indexBuffer = new Uint16Array(3 * 10920);
|
||||||
|
geometry.setIndex(new THREE.BufferAttribute(indexBuffer, 1));
|
||||||
|
geometry.getIndex().dynamic = true;
|
||||||
|
this.update(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaTime: number) {
|
||||||
|
let state = this.state;
|
||||||
|
let skeleton = this.skeleton;
|
||||||
|
|
||||||
|
state.update(deltaTime);
|
||||||
|
state.apply(skeleton);
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
this.updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateGeometry() {
|
||||||
|
let geometry = <THREE.BufferGeometry>this.geometry;
|
||||||
|
geometry.drawRange.start = 0;
|
||||||
|
geometry.drawRange.count = 0;
|
||||||
|
this._vertexBuffer.needsUpdate = true;
|
||||||
|
geometry.getIndex().needsUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
spine-ts/threejs/src/ThreeJsTexture.ts
Normal file
42
spine-ts/threejs/src/ThreeJsTexture.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
module spine.threejs {
|
||||||
|
export class ThreeJsTexture extends Texture {
|
||||||
|
texture: THREE.Texture;
|
||||||
|
|
||||||
|
constructor (image: HTMLImageElement) {
|
||||||
|
super(image);
|
||||||
|
this.texture = new THREE.Texture(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
|
||||||
|
this.texture.minFilter = ThreeJsTexture.toThreeJsTextureFilter(minFilter);
|
||||||
|
this.texture.magFilter = ThreeJsTexture.toThreeJsTextureFilter(magFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
|
||||||
|
this.texture.wrapS = ThreeJsTexture.toThreeJsTextureWrap(uWrap);
|
||||||
|
this.texture.wrapT = ThreeJsTexture.toThreeJsTextureWrap(vWrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose () {
|
||||||
|
this.texture.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
static toThreeJsTextureFilter(filter: TextureFilter) {
|
||||||
|
if (filter === TextureFilter.Linear) return THREE.LinearFilter;
|
||||||
|
else if (filter === TextureFilter.MipMap) return THREE.LinearMipMapLinearFilter;
|
||||||
|
else if (filter === TextureFilter.MipMapLinearLinear) return THREE.LinearMipMapLinearFilter;
|
||||||
|
else if (filter === TextureFilter.MipMapLinearNearest) return THREE.LinearMipMapNearestFilter;
|
||||||
|
else if (filter === TextureFilter.MipMapNearestLinear) return THREE.NearestMipMapLinearFilter;
|
||||||
|
else if (filter === TextureFilter.MipMapNearestNearest) return THREE.NearestMipMapNearestFilter;
|
||||||
|
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;
|
||||||
|
else if (wrap === TextureWrap.Repeat) return THREE.RepeatWrapping;
|
||||||
|
else throw new Error("Unknown texture wrap: " + wrap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user