diff --git a/serve/src/index.js b/serve/src/index.js index 48c88154..d272dcf1 100644 --- a/serve/src/index.js +++ b/serve/src/index.js @@ -2,6 +2,7 @@ let app = new PIXI.Application({ backgroundColor: 0xdddddd, resizeTo: window, antialias: true }) document.body.appendChild(app.view) +globalThis.__PIXI_APP__ = app let control = new PIXI3D.CameraOrbitControl(app.view) control.enableDamping = true diff --git a/src/gltf/animation/gltf-cubic-spline.ts b/src/gltf/animation/gltf-cubic-spline.ts index 4a9d3533..63ee550c 100644 --- a/src/gltf/animation/gltf-cubic-spline.ts +++ b/src/gltf/animation/gltf-cubic-spline.ts @@ -1,10 +1,12 @@ -import { glTFInterpolation } from "./gltf-interpolation" +import { glTFInterpolation, getDenormalizeFunction } from "./gltf-interpolation" export class glTFCubicSpline implements glTFInterpolation { private _data: Float32Array + private _denormalize: (data: Float32Array) => Float32Array constructor(private _input: ArrayLike, private _output: ArrayLike, private _stride: number) { this._data = new Float32Array(_stride) + this._denormalize = getDenormalizeFunction(this._output, this._stride) } interpolate(frame: number, position: number) { @@ -15,7 +17,7 @@ export class glTFCubicSpline implements glTFInterpolation { this._data[i] = glTFCubicSpline.calculate( position, this._output[pos1 + i + 1 * this._stride], this._output[pos2 + i + 1 * this._stride], diff * this._output[pos2 + i], diff * this._output[pos1 + i + 2 * this._stride]) } - return this._data + return this._denormalize(this._data) } static calculate(t: number, p0: number, p1: number, m0: number, m1: number) { diff --git a/src/gltf/animation/gltf-interpolation.ts b/src/gltf/animation/gltf-interpolation.ts index 63daf634..34b950ec 100644 --- a/src/gltf/animation/gltf-interpolation.ts +++ b/src/gltf/animation/gltf-interpolation.ts @@ -8,4 +8,73 @@ export interface glTFInterpolation { * @param position The position within the animation frame (between 0-1). */ interpolate(frame: number, position: number): Float32Array +} + +export function getDenormalizeFunction(output: ArrayLike, stride: number): (data: Float32Array) => Float32Array { + switch ( output.constructor ) { + + case Float32Array: + + return (data: Float32Array) => data; + + case Uint32Array: + + return (data: Float32Array) => { + for (let i = 0; i < stride; i++) { + data[i] = data[i] / 4294967295.0; + } + return data; + }; + + case Uint16Array: + + return (data: Float32Array) => { + for (let i = 0; i < stride; i++) { + data[i] = data[i] / 65535.0; + } + return data; + }; + + case Uint8Array: + + return (data: Float32Array) => { + for (let i = 0; i < stride; i++) { + data[i] = data[i] / 255.0; + } + return data; + }; + + case Int32Array: + + return (data: Float32Array) => { + for (let i = 0; i < stride; i++) { + data[i] = Math.max( data[i] / 2147483647.0, - 1.0 ); + } + return data; + }; + + case Int16Array: + + return (data: Float32Array) => { + for (let i = 0; i < stride; i++) { + data[i] = Math.max( data[i] / 32767.0, - 1.0 ); + } + return data; + }; + + case Int8Array: + + + return (data: Float32Array) => { + for (let i = 0; i < stride; i++) { + data[i] = Math.max( data[i] / 127.0, - 1.0 ); + } + return data; + }; + + default: + + throw new Error( 'Invalid component type.' ); + + } } \ No newline at end of file diff --git a/src/gltf/animation/gltf-linear.ts b/src/gltf/animation/gltf-linear.ts index 781a52cf..40e772b9 100644 --- a/src/gltf/animation/gltf-linear.ts +++ b/src/gltf/animation/gltf-linear.ts @@ -1,10 +1,12 @@ -import { glTFInterpolation } from "./gltf-interpolation" +import { glTFInterpolation, getDenormalizeFunction } from "./gltf-interpolation" export class glTFLinear implements glTFInterpolation { private _data: Float32Array + private _denormalize: (data: Float32Array) => Float32Array constructor(private _output: ArrayLike, private _stride: number) { this._data = new Float32Array(_stride) + this._denormalize = getDenormalizeFunction(this._output, this._stride) } interpolate(frame: number, position: number) { @@ -17,6 +19,6 @@ export class glTFLinear implements glTFInterpolation { this._data[i] = this._output[pos1 + i] } } - return this._data + return this._denormalize(this._data) } } \ No newline at end of file diff --git a/src/gltf/animation/gltf-step.ts b/src/gltf/animation/gltf-step.ts index 2f2518a2..42316447 100644 --- a/src/gltf/animation/gltf-step.ts +++ b/src/gltf/animation/gltf-step.ts @@ -1,16 +1,18 @@ -import { glTFInterpolation } from "./gltf-interpolation" +import { glTFInterpolation, getDenormalizeFunction } from "./gltf-interpolation" export class glTFStep implements glTFInterpolation { private _data: Float32Array + private _denormalize: (data: Float32Array) => Float32Array constructor(private _output: ArrayLike, private _stride: number) { this._data = new Float32Array(_stride) + this._denormalize = getDenormalizeFunction(this._output, this._stride) } interpolate(frame: number) { for (let i = 0; i < this._stride; i++) { this._data[i] = this._output[frame * this._stride + i] } - return this._data + return this._denormalize(this._data) } } \ No newline at end of file diff --git a/src/gltf/gltf-attribute.ts b/src/gltf/gltf-attribute.ts index 3fdcccd2..b8e314c6 100644 --- a/src/gltf/gltf-attribute.ts +++ b/src/gltf/gltf-attribute.ts @@ -2,23 +2,23 @@ * Represents data for a specific geometry attribute. */ export class glTFAttribute { - constructor(public buffer: Uint32Array | Float32Array | Int8Array | Uint8Array | Int16Array | Uint16Array, public componentType: number, public stride = 0, public componentCount: number, public min?: number[], public max?: number[]) { + constructor(public buffer: Uint32Array | Float32Array | Int8Array | Uint8Array | Int16Array | Uint16Array, public componentType: number, public stride = 0, public componentCount: number, public normalized: boolean = false, public min?: number[], public max?: number[]) { } - static from(componentType: number, componentCount: number, buffer: ArrayBuffer, offset: number, size: number, stride?: number, min?: number[], max?: number[]) { + static from(componentType: number, componentCount: number, buffer: ArrayBuffer, offset: number, size: number, stride?: number, normalized: boolean = false, min?: number[], max?: number[]) { switch (componentType) { case 5125: return new glTFAttribute( - new Uint32Array(buffer, offset, size), componentType, stride, componentCount, min, max) + new Uint32Array(buffer, offset, size), componentType, stride, componentCount, normalized, min, max) case 5126: return new glTFAttribute( - new Float32Array(buffer, offset, size), componentType, stride, componentCount, min, max) + new Float32Array(buffer, offset, size), componentType, stride, componentCount, normalized, min, max) case 5120: return new glTFAttribute( - new Int8Array(buffer, offset, size), componentType, stride, componentCount, min, max) + new Int8Array(buffer, offset, size), componentType, stride, componentCount, normalized, min, max) case 5121: return new glTFAttribute( - new Uint8Array(buffer, offset, size), componentType, stride, componentCount, min, max) + new Uint8Array(buffer, offset, size), componentType, stride, componentCount, normalized, min, max) case 5122: return new glTFAttribute( - new Int16Array(buffer, offset, size), componentType, stride, componentCount, min, max) + new Int16Array(buffer, offset, size), componentType, stride, componentCount, normalized, min, max) case 5123: return new glTFAttribute( - new Uint16Array(buffer, offset, size), componentType, stride, componentCount, min, max) + new Uint16Array(buffer, offset, size), componentType, stride, componentCount, normalized, min, max) default: { throw new Error(`PIXI3D: Unknown component type "${componentType}".`) } diff --git a/src/gltf/gltf-parser.ts b/src/gltf/gltf-parser.ts index 6b755e82..ebfb32c6 100644 --- a/src/gltf/gltf-parser.ts +++ b/src/gltf/gltf-parser.ts @@ -80,9 +80,10 @@ export class glTFParser { size = bufferView.byteStride / componentSize[accessor.componentType] * (accessor.count - 1) + componentCount[accessor.type] } let buffer = this._asset.buffers[bufferView.buffer] + const normalized = accessor.normalized === true; return glTFAttribute.from( - accessor.componentType, componentCount[accessor.type], buffer, offset, size, bufferView.byteStride, accessor.min, accessor.max) + accessor.componentType, componentCount[accessor.type], buffer, offset, size, bufferView.byteStride, normalized, accessor.min, accessor.max) } /** diff --git a/src/material/standard/standard-shader.ts b/src/material/standard/standard-shader.ts index d8c52439..cce6684b 100644 --- a/src/material/standard/standard-shader.ts +++ b/src/material/standard/standard-shader.ts @@ -34,31 +34,31 @@ export class StandardShader extends MeshShader { let positions = geometry.targets[i].positions if (positions) { result.addAttribute(`a_Target_Position${i}`, new Buffer(positions.buffer), - 3, false, positions.componentType, positions.stride) + 3, positions.normalized, positions.componentType, positions.stride) } let normals = geometry.targets[i].normals if (normals) { result.addAttribute(`a_Target_Normal${i}`, new Buffer(normals.buffer), - 3, false, normals.componentType, normals.stride) + 3, normals.normalized, normals.componentType, normals.stride) } let tangents = geometry.targets[i].tangents if (tangents) { result.addAttribute(`a_Target_Tangent${i}`, new Buffer(tangents.buffer), - 3, false, tangents.componentType, tangents.stride) + 3, tangents.normalized, tangents.componentType, tangents.stride) } } } if (geometry.uvs && geometry.uvs[1]) { result.addAttribute("a_UV2", new Buffer(geometry.uvs[1].buffer), - 2, false, geometry.uvs[1].componentType, geometry.uvs[1].stride) + 2, geometry.uvs[1].normalized, geometry.uvs[1].componentType, geometry.uvs[1].stride) } if (geometry.joints) { result.addAttribute("a_Joint1", new Buffer(geometry.joints.buffer), - 4, false, geometry.joints.componentType, geometry.joints.stride) + 4, geometry.joints.normalized, geometry.joints.componentType, geometry.joints.stride) } if (geometry.weights) { result.addAttribute("a_Weight1", new Buffer(geometry.weights.buffer), - 4, false, geometry.weights.componentType, geometry.weights.stride) + 4, geometry.weights.normalized, geometry.weights.componentType, geometry.weights.stride) } return result } diff --git a/src/mesh/geometry/mesh-geometry-attribute.ts b/src/mesh/geometry/mesh-geometry-attribute.ts index 0f77cf75..0f49d90f 100644 --- a/src/mesh/geometry/mesh-geometry-attribute.ts +++ b/src/mesh/geometry/mesh-geometry-attribute.ts @@ -28,4 +28,8 @@ export interface MeshGeometryAttribute { * The number of elements in this attribute. */ componentCount?: number + /** + * Is buffer data normalized in this attribute. + */ + normalized: boolean } \ No newline at end of file diff --git a/src/mesh/mesh-shader.ts b/src/mesh/mesh-shader.ts index 8a93053c..54131e6b 100644 --- a/src/mesh/mesh-shader.ts +++ b/src/mesh/mesh-shader.ts @@ -33,23 +33,23 @@ export class MeshShader extends Shader { } if (geometry.positions) { result.addAttribute("a_Position", new Buffer(geometry.positions.buffer), - 3, false, geometry.positions.componentType, geometry.positions.stride) + 3, geometry.positions.normalized, geometry.positions.componentType, geometry.positions.stride) } if (geometry.uvs && geometry.uvs[0]) { result.addAttribute("a_UV1", new Buffer(geometry.uvs[0].buffer), - 2, false, geometry.uvs[0].componentType, geometry.uvs[0].stride) + 2, geometry.uvs[0].normalized, geometry.uvs[0].componentType, geometry.uvs[0].stride) } if (geometry.normals) { result.addAttribute("a_Normal", new Buffer(geometry.normals.buffer), - 3, false, geometry.normals.componentType, geometry.normals.stride) + 3, geometry.normals.normalized, geometry.normals.componentType, geometry.normals.stride) } if (geometry.tangents) { result.addAttribute("a_Tangent", new Buffer(geometry.tangents.buffer), - 4, false, geometry.tangents.componentType, geometry.tangents.stride) + 4, geometry.tangents.normalized, geometry.tangents.componentType, geometry.tangents.stride) } if (geometry.colors) { result.addAttribute("a_Color", new Buffer(geometry.colors.buffer), - geometry.colors.componentCount, true, geometry.colors.componentType, geometry.colors.stride) + geometry.colors.componentCount, geometry.colors.normalized, geometry.colors.componentType, geometry.colors.stride) } return result }