From 8e84ad990d4ca81da366966372e61ebf8c9d2830 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 4 Sep 2023 09:54:05 +0200 Subject: [PATCH] |threejs] Add logarithmic depth buffer example. --- spine-ts/index.html | 231 +++++++--- spine-ts/spine-threejs/example/index.html | 241 +++++----- .../example/logarithmic-depth-buffer.html | 186 ++++++++ spine-ts/spine-threejs/src/SkeletonMesh.ts | 434 ++++++++++-------- 4 files changed, 712 insertions(+), 380 deletions(-) create mode 100644 spine-ts/spine-threejs/example/logarithmic-depth-buffer.html diff --git a/spine-ts/index.html b/spine-ts/index.html index c038070d1..cbee081a6 100644 --- a/spine-ts/index.html +++ b/spine-ts/index.html @@ -1,79 +1,158 @@ + + + + spine-ts Examples + + - - - - spine-ts Examples - - - - -

spine-ts Examples

- - - - \ No newline at end of file + +

spine-ts Examples

+ + + diff --git a/spine-ts/spine-threejs/example/index.html b/spine-ts/spine-threejs/example/index.html index ba95db20d..d6bf3daea 100644 --- a/spine-ts/spine-threejs/example/index.html +++ b/spine-ts/spine-threejs/example/index.html @@ -1,141 +1,150 @@ + + + spine-threejs + + + + + - canvas { - position: absolute; - width: 100%; - height: 100%; - } - + + - - - \ No newline at end of file + init(); + })(); + + + diff --git a/spine-ts/spine-threejs/example/logarithmic-depth-buffer.html b/spine-ts/spine-threejs/example/logarithmic-depth-buffer.html new file mode 100644 index 000000000..145efe204 --- /dev/null +++ b/spine-ts/spine-threejs/example/logarithmic-depth-buffer.html @@ -0,0 +1,186 @@ + + + + spine-threejs + + + + + + + + + + diff --git a/spine-ts/spine-threejs/src/SkeletonMesh.ts b/spine-ts/spine-threejs/src/SkeletonMesh.ts index de4476954..5769dc47f 100644 --- a/spine-ts/spine-threejs/src/SkeletonMesh.ts +++ b/spine-ts/spine-threejs/src/SkeletonMesh.ts @@ -27,16 +27,33 @@ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -import { AnimationState, AnimationStateData, BlendMode, ClippingAttachment, Color, MeshAttachment, NumberArrayLike, RegionAttachment, Skeleton, SkeletonClipping, SkeletonData, TextureAtlasRegion, Utils, Vector2 } from "@esotericsoftware/spine-core"; +import { + AnimationState, + AnimationStateData, + BlendMode, + ClippingAttachment, + Color, + MeshAttachment, + NumberArrayLike, + RegionAttachment, + Skeleton, + SkeletonClipping, + SkeletonData, + TextureAtlasRegion, + Utils, + Vector2, +} from "@esotericsoftware/spine-core"; import { MeshBatcher } from "./MeshBatcher"; import * as THREE from "three"; import { ThreeJsTexture } from "./ThreeJsTexture"; -export type SkeletonMeshMaterialParametersCustomizer = (materialParameters: THREE.ShaderMaterialParameters) => void; +export type SkeletonMeshMaterialParametersCustomizer = ( + materialParameters: THREE.ShaderMaterialParameters +) => void; export class SkeletonMeshMaterial extends THREE.ShaderMaterial { - constructor (customizer: SkeletonMeshMaterialParametersCustomizer) { - let vertexShader = ` + constructor(customizer: SkeletonMeshMaterialParametersCustomizer) { + let vertexShader = ` attribute vec4 color; varying vec2 vUv; varying vec4 vColor; @@ -46,7 +63,7 @@ export class SkeletonMeshMaterial extends THREE.ShaderMaterial { gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0); } `; - let fragmentShader = ` + let fragmentShader = ` uniform sampler2D map; #ifdef USE_SPINE_ALPHATEST uniform float alphaTest; @@ -61,212 +78,253 @@ export class SkeletonMeshMaterial extends THREE.ShaderMaterial { } `; - let parameters: THREE.ShaderMaterialParameters = { - uniforms: { - map: { value: null }, - }, - vertexShader: vertexShader, - fragmentShader: fragmentShader, - side: THREE.DoubleSide, - transparent: true, - depthWrite: false, - 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); - }; + 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); + } } export class SkeletonMesh extends THREE.Object3D { - tempPos: Vector2 = new Vector2(); - tempUv: Vector2 = new Vector2(); - tempLight = new Color(); - tempDark = new Color(); - skeleton: Skeleton; - state: AnimationState; - zOffset: number = 0.1; + tempPos: Vector2 = new Vector2(); + tempUv: Vector2 = new Vector2(); + tempLight = new Color(); + tempDark = new Color(); + skeleton: Skeleton; + state: AnimationState; + zOffset: number = 0.1; - private batches = new Array(); - private nextBatchIndex = 0; - private clipper: SkeletonClipping = new SkeletonClipping(); + private batches = new Array(); + private nextBatchIndex = 0; + private clipper: SkeletonClipping = new SkeletonClipping(); - static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; - static VERTEX_SIZE = 2 + 2 + 4; + static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + static VERTEX_SIZE = 2 + 2 + 4; - private vertices = Utils.newFloatArray(1024); - private tempColor = new Color(); + private vertices = Utils.newFloatArray(1024); + private tempColor = new Color(); - constructor (skeletonData: SkeletonData, private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = (material) => { }) { - super(); + constructor( + skeletonData: SkeletonData, + private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = ( + material + ) => {} + ) { + super(); - this.skeleton = new Skeleton(skeletonData); - let animData = new AnimationStateData(skeletonData); - this.state = new AnimationState(animData); - } + this.skeleton = new Skeleton(skeletonData); + let animData = new AnimationStateData(skeletonData); + this.state = new AnimationState(animData); + } - update (deltaTime: number) { - let state = this.state; - let skeleton = this.skeleton; + update(deltaTime: number) { + let state = this.state; + let skeleton = this.skeleton; - state.update(deltaTime); - state.apply(skeleton); - skeleton.updateWorldTransform(); + state.update(deltaTime); + state.apply(skeleton); + skeleton.updateWorldTransform(); - this.updateGeometry(); - } + this.updateGeometry(); + } - dispose () { - for (var i = 0; i < this.batches.length; i++) { - this.batches[i].dispose(); - } - } + dispose() { + for (var i = 0; i < this.batches.length; i++) { + this.batches[i].dispose(); + } + } - private clearBatches () { - for (var i = 0; i < this.batches.length; i++) { - this.batches[i].clear(); - this.batches[i].visible = false; - } - this.nextBatchIndex = 0; - } + private clearBatches() { + for (var i = 0; i < this.batches.length; i++) { + this.batches[i].clear(); + this.batches[i].visible = false; + } + this.nextBatchIndex = 0; + } - private nextBatch () { - if (this.batches.length == this.nextBatchIndex) { - let batch = new MeshBatcher(10920, this.materialCustomerizer); - this.add(batch); - this.batches.push(batch); - } - let batch = this.batches[this.nextBatchIndex++]; - batch.visible = true; - return batch; - } + private nextBatch() { + if (this.batches.length == this.nextBatchIndex) { + let batch = new MeshBatcher(10920, this.materialCustomerizer); + this.add(batch); + this.batches.push(batch); + } + let batch = this.batches[this.nextBatchIndex++]; + batch.visible = true; + return batch; + } - private updateGeometry () { - this.clearBatches(); + private updateGeometry() { + this.clearBatches(); - let tempPos = this.tempPos; - let tempUv = this.tempUv; - let tempLight = this.tempLight; - let tempDark = this.tempDark; - let clipper = this.clipper; + let tempPos = this.tempPos; + let tempUv = this.tempUv; + let tempLight = this.tempLight; + let tempDark = this.tempDark; + let clipper = this.clipper; - let vertices: NumberArrayLike = this.vertices; - let triangles: Array | null = null; - let uvs: NumberArrayLike | null = null; - let drawOrder = this.skeleton.drawOrder; - let batch = this.nextBatch(); - batch.begin(); - 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 slot = drawOrder[i]; - if (!slot.bone.active) { - clipper.clipEndWithSlot(slot); - continue; - } - let attachment = slot.getAttachment(); - let attachmentColor: Color | null; - let texture: ThreeJsTexture | null; - let numFloats = 0; - if (attachment instanceof RegionAttachment) { - let region = attachment; - attachmentColor = region.color; - vertices = this.vertices; - numFloats = vertexSize * 4; - region.computeWorldVertices(slot, vertices, 0, vertexSize); - triangles = SkeletonMesh.QUAD_TRIANGLES; - uvs = region.uvs; - texture = region.region!.texture; - } else if (attachment instanceof MeshAttachment) { - let mesh = attachment; - attachmentColor = mesh.color; - vertices = this.vertices; - numFloats = (mesh.worldVerticesLength >> 1) * vertexSize; - if (numFloats > vertices.length) { - vertices = this.vertices = Utils.newFloatArray(numFloats); - } - mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, vertexSize); - triangles = mesh.triangles; - uvs = mesh.uvs; - texture = mesh.region!.texture; - } else if (attachment instanceof ClippingAttachment) { - let clip = (attachment); - clipper.clipStart(slot, clip); - continue; - } else { - clipper.clipEndWithSlot(slot); - continue; - } + let vertices: NumberArrayLike = this.vertices; + let triangles: Array | null = null; + let uvs: NumberArrayLike | null = null; + let drawOrder = this.skeleton.drawOrder; + let batch = this.nextBatch(); + batch.begin(); + 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 slot = drawOrder[i]; + if (!slot.bone.active) { + clipper.clipEndWithSlot(slot); + continue; + } + let attachment = slot.getAttachment(); + let attachmentColor: Color | null; + let texture: ThreeJsTexture | null; + let numFloats = 0; + if (attachment instanceof RegionAttachment) { + let region = attachment; + attachmentColor = region.color; + vertices = this.vertices; + numFloats = vertexSize * 4; + region.computeWorldVertices(slot, vertices, 0, vertexSize); + triangles = SkeletonMesh.QUAD_TRIANGLES; + uvs = region.uvs; + texture = region.region!.texture; + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + attachmentColor = mesh.color; + vertices = this.vertices; + numFloats = (mesh.worldVerticesLength >> 1) * vertexSize; + if (numFloats > vertices.length) { + vertices = this.vertices = Utils.newFloatArray(numFloats); + } + mesh.computeWorldVertices( + slot, + 0, + mesh.worldVerticesLength, + vertices, + 0, + vertexSize + ); + triangles = mesh.triangles; + uvs = mesh.uvs; + texture = mesh.region!.texture; + } else if (attachment instanceof ClippingAttachment) { + let clip = attachment; + clipper.clipStart(slot, clip); + continue; + } else { + clipper.clipEndWithSlot(slot); + continue; + } - if (texture != null) { - let skeleton = slot.bone.skeleton; - let skeletonColor = skeleton.color; - let slotColor = slot.color; - let alpha = skeletonColor.a * slotColor.a * attachmentColor.a; - let color = this.tempColor; - color.set(skeletonColor.r * slotColor.r * attachmentColor.r, - skeletonColor.g * slotColor.g * attachmentColor.g, - skeletonColor.b * slotColor.b * attachmentColor.b, - alpha); + if (texture != null) { + let skeleton = slot.bone.skeleton; + let skeletonColor = skeleton.color; + let slotColor = slot.color; + let alpha = skeletonColor.a * slotColor.a * attachmentColor.a; + let color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * attachmentColor.r, + skeletonColor.g * slotColor.g * attachmentColor.g, + skeletonColor.b * slotColor.b * attachmentColor.b, + alpha + ); - let finalVertices: NumberArrayLike; - let finalVerticesLength: number; - let finalIndices: NumberArrayLike; - let finalIndicesLength: number; + let finalVertices: NumberArrayLike; + let finalVerticesLength: number; + let finalIndices: NumberArrayLike; + let finalIndicesLength: number; - if (clipper.isClipping()) { - clipper.clipTriangles(vertices, numFloats, triangles, triangles.length, uvs, color, tempLight, false); - let clippedVertices = clipper.clippedVertices; - let clippedTriangles = clipper.clippedTriangles; - finalVertices = clippedVertices; - finalVerticesLength = clippedVertices.length; - finalIndices = clippedTriangles; - 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]; - } - finalVertices = vertices; - finalVerticesLength = numFloats; - finalIndices = triangles; - finalIndicesLength = triangles.length; - } + if (clipper.isClipping()) { + clipper.clipTriangles( + vertices, + numFloats, + triangles, + triangles.length, + uvs, + color, + tempLight, + false + ); + let clippedVertices = clipper.clippedVertices; + let clippedTriangles = clipper.clippedTriangles; + finalVertices = clippedVertices; + finalVerticesLength = clippedVertices.length; + finalIndices = clippedTriangles; + 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]; + } + finalVertices = vertices; + finalVerticesLength = numFloats; + finalIndices = triangles; + finalIndicesLength = triangles.length; + } - if (finalVerticesLength == 0 || finalIndicesLength == 0) { - clipper.clipEndWithSlot(slot); - continue; - } + if (finalVerticesLength == 0 || finalIndicesLength == 0) { + clipper.clipEndWithSlot(slot); + continue; + } - // Start new batch if this one can't hold vertices/indices - if (!batch.canBatch(finalVerticesLength / SkeletonMesh.VERTEX_SIZE, finalIndicesLength)) { - batch.end(); - batch = this.nextBatch(); - batch.begin(); - } + // Start new batch if this one can't hold vertices/indices + if ( + !batch.canBatch( + finalVerticesLength / SkeletonMesh.VERTEX_SIZE, + finalIndicesLength + ) + ) { + batch.end(); + batch = this.nextBatch(); + batch.begin(); + } - const slotBlendMode = slot.data.blendMode; - const slotTexture = texture.texture; - const materialGroup = batch.findMaterialGroup(slotTexture, slotBlendMode); + const slotBlendMode = slot.data.blendMode; + const slotTexture = texture.texture; + const materialGroup = batch.findMaterialGroup( + slotTexture, + slotBlendMode + ); - batch.addMaterialGroup(finalIndicesLength, materialGroup); - batch.batch(finalVertices, finalVerticesLength, finalIndices, finalIndicesLength, z); - z += zOffset; - } + batch.addMaterialGroup(finalIndicesLength, materialGroup); + batch.batch( + finalVertices, + finalVerticesLength, + finalIndices, + finalIndicesLength, + z + ); + z += zOffset; + } - clipper.clipEndWithSlot(slot); - } - clipper.clipEnd(); - batch.end(); - } + clipper.clipEndWithSlot(slot); + } + clipper.clipEnd(); + batch.end(); + } }