Commit 4abf3278 authored by wjf's avatar wjf

l

parent 5083036a
{
"liveServer.settings.port": 5501
}
\ No newline at end of file
......@@ -8102,767 +8102,6 @@ export class SoundChannel extends EventDispatcher {
readonly position: number;
}
export class Vector3 {
x: number;
y: number;
z: number;
constructor(x?: number, y?: number, z?: number);
set(x: number, y: number, z: number): this;
copy(v: Vector3): this;
clone(): Vector3;
add(v: any): this;
addScalar(s: any): this;
addVectors(a: any, b: any): this;
addScaledVector(v: any, s: any): this;
sub(v: any): this;
subScalar(s: any): this;
subVectors(a: any, b: any): this;
multiplyScalar(scalar: number): this;
multiplyVectors(a: Vector3, b: Vector3): this;
cross(v: any): this;
crossVectors(a: any, b: any): this;
/**
* 长度
*/
length(): number;
lengthSq(): number;
/**
* 标准化,长度为1
*/
normalize(): this;
/**
*
* @param m
*/
applyMatrix4(m: Matrix4): this;
/**
* 从矩阵获得位置
* @param m
*/
setFromMatrixPosition(m: Matrix4): this;
/**
* 从矩阵获得缩放值
* @param m
*/
setFromMatrixScale(m: Matrix4): this;
setFromMatrixColumn(m: Matrix4, index: number): this;
transformDirection(m: Matrix4): this;
/**
* 转换成屏幕坐标,范围-1到1,可根据stage转换成stage上坐标,或者canvas坐标
* @param camera
*/
project(camera: Camera): this;
fromArray(array: number[] | Float32Array, offset?: number): this;
toArray(array?: number[], offset?: number): number[];
}
export class Quaternion {
private _x;
private _y;
private _z;
private _w;
constructor(x?: number, y?: number, z?: number, w?: number);
static slerp(qa: any, qb: any, qm: any, t: any): any;
static slerpFlat(dst: any, dstOffset: any, src0: any, srcOffset0: any, src1: any, srcOffset1: any, t: any): void;
x: number;
y: number;
z: number;
w: number;
set(x: any, y: any, z: any, w: any): this;
clone(): Quaternion;
copy(quaternion: any): this;
setFromEuler(euler: any, update?: any): this;
setFromAxisAngle(axis: any, angle: any): this;
setFromRotationMatrix(m: any): this;
setFromUnitVectors: (vFrom: any, vTo: any) => any;
angleTo(q: any): number;
rotateTowards(q: any, step: any): this;
inverse(): this;
conjugate(): this;
dot(v: any): number;
lengthSq(): number;
length(): number;
normalize(): this;
multiply(q: any, p: any): this;
premultiply(q: any): this;
multiplyQuaternions(a: any, b: any): this;
slerp(qb: any, t: any): this;
equals(quaternion: any): boolean;
fromArray(array: any, offset: any): this;
toArray(array: any, offset: any): any;
onChange(callback: any): this;
private onChangeCallback;
}
export class Matrix4 {
elements: Float32Array;
constructor();
/**
* 初始化本矩阵
*/
setIdentity(): this;
set(n11: any, n12: any, n13: any, n14: any, n21: any, n22: any, n23: any, n24: any, n31: any, n32: any, n33: any, n34: any, n41: any, n42: any, n43: any, n44: any): this;
copy(src: Matrix4): this;
clone(): Matrix4;
equals(matrix: any): boolean;
fromArray(array: any, offset?: number): this;
toArray(array?: any[], offset?: number): any[];
/**
* Multiply the matrix from the right.
* @param other The multiply matrix
* @return this
*/
concat(other: Matrix4): this;
multiply(m: any): this;
premultiply(m: any): this;
multiplyMatrices(a: any, b: any): this;
/**
* Multiply the three-dimensional vector.
* @param pos The multiply vector
* @return The result of multiplication(Float32Array)
*/
multiplyVector3(pos: Vector3): Vector3;
/**
* Multiply the four-dimensional vector.
* @param pos The multiply vector
* @return The result of multiplication(Float32Array)
*/
/**
* Transpose the matrix.转置
* @return this
*/
transpose(): this;
/**
* Calculate the inverse matrix of specified matrix, and set to this.将一矩阵的逆赋给自己
* @param other The source matrix
* @return this
*/
setInverseOf(other: Matrix4): this;
/**
* Calculate the inverse matrix of this, and set to this.
* @return this
*/
invert(): this;
/**
* Set the orthographic projection matrix.正交投影矩阵
* @param left The coordinate of the left of clipping plane.
* @param right The coordinate of the right of clipping plane.
* @param bottom The coordinate of the bottom of clipping plane.
* @param top The coordinate of the top top clipping plane.
* @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
* @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
* @return this
*/
setOrtho(left: number, right: number, bottom: number, top: number, near: number, far: number): this;
/**
* Multiply the orthographic projection matrix from the right.
* @param left The coordinate of the left of clipping plane.
* @param right The coordinate of the right of clipping plane.
* @param bottom The coordinate of the bottom of clipping plane.
* @param top The coordinate of the top top clipping plane.
* @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
* @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
* @return this
*/
ortho(left: any, right: any, bottom: any, top: any, near: any, far: any): this;
/**
* Set the perspective projection matrix.
* @param left The coordinate of the left of clipping plane.
* @param right The coordinate of the right of clipping plane.
* @param bottom The coordinate of the bottom of clipping plane.
* @param top The coordinate of the top top clipping plane.
* @param near The distances to the nearer depth clipping plane. This value must be plus value.
* @param far The distances to the farther depth clipping plane. This value must be plus value.
* @return this
*/
setFrustum(left: any, right: any, bottom: any, top: any, near: any, far: any): this;
/**
* Multiply the perspective projection matrix from the right.
* @param left The coordinate of the left of clipping plane.
* @param right The coordinate of the right of clipping plane.
* @param bottom The coordinate of the bottom of clipping plane.
* @param top The coordinate of the top top clipping plane.
* @param near The distances to the nearer depth clipping plane. This value must be plus value.
* @param far The distances to the farther depth clipping plane. This value must be plus value.
* @return this
*/
frustum(left: any, right: any, bottom: any, top: any, near: any, far: any): this;
/**
* Set the perspective projection matrix by fovy and aspect.
* @param fovy The angle between the upper and lower sides of the frustum.
* @param aspect The aspect ratio of the frustum. (width/height)
* @param near The distances to the nearer depth clipping plane. This value must be plus value.
* @param far The distances to the farther depth clipping plane. This value must be plus value.
* @return this
*/
setPerspective(fovy: number, aspect: number, near: number, far: number): this;
makePerspective(left: any, right: any, top: any, bottom: any, near: any, far: any): this;
/**
* Multiply the perspective projection matrix from the right.
* @param fovy The angle between the upper and lower sides of the frustum.
* @param aspect The aspect ratio of the frustum. (width/height)
* @param near The distances to the nearer depth clipping plane. This value must be plus value.
* @param far The distances to the farther depth clipping plane. This value must be plus value.
* @return this
*/
perspective(fovy: any, aspect: any, near: any, far: any): this;
/**
* Set the matrix for scaling.
* @param x The scale factor along the X axis
* @param y The scale factor along the Y axis
* @param z The scale factor along the Z axis
* @return this
*/
setScale(x: any, y: any, z: any): this;
/**
* Multiply the matrix for scaling from the right.
* @param x The scale factor along the X axis
* @param y The scale factor along the Y axis
* @param z The scale factor along the Z axis
* @return this
*/
scale(x: any, y: any, z: any): this;
/**
* Set the matrix for translation.
* @param x The X value of a translation.
* @param y The Y value of a translation.
* @param z The Z value of a translation.
* @return this
*/
setTranslate(x: any, y: any, z: any): this;
/**
* Multiply the matrix for translation from the right.
* @param x The X value of a translation.
* @param y The Y value of a translation.
* @param z The Z value of a translation.
* @return this
*/
translate(x: any, y: any, z: any): this;
/**
* Set the matrix for rotation.
* The vector of rotation axis may not be normalized.
* @param angle The angle of rotation (degrees)
* @param x The X coordinate of vector of rotation axis.
* @param y The Y coordinate of vector of rotation axis.
* @param z The Z coordinate of vector of rotation axis.
* @return this
*/
setRotate(angle: any, x: any, y: any, z: any): this;
/**
* Multiply the matrix for rotation from the right.
* The vector of rotation axis may not be normalized.
* @param angle The angle of rotation (degrees)
* @param x The X coordinate of vector of rotation axis.
* @param y The Y coordinate of vector of rotation axis.
* @param z The Z coordinate of vector of rotation axis.
* @return this
*/
rotate(angle: any, x: any, y: any, z: any): this;
/**
* Set the viewing matrix.
* @param eyeX, eyeY, eyeZ The position of the eye point.
* @param centerX, centerY, centerZ The position of the reference point.
* @param upX, upY, upZ The direction of the up vector.
* @return this
*/
setLookAt(eyeX: any, eyeY: any, eyeZ: any, centerX: any, centerY: any, centerZ: any, upX: any, upY: any, upZ: any): this;
lookAt(eye: Vector3, target: Vector3, up: Vector3): this;
/**
* Multiply the matrix for project vertex to plane from the right.
* @param plane The array[A, B, C, D] of the equation of plane "Ax + By + Cz + D = 0".
* @param light The array which stored coordinates of the light. if light[3]=0, treated as parallel light.
* @return this
*/
dropShadow(plane: any, light: any): this;
/**
* Multiply the matrix for project vertex to plane from the right.(Projected by parallel light.)
* @param normX, normY, normZ The normal vector of the plane.(Not necessary to be normalized.)
* @param planeX, planeY, planeZ The coordinate of arbitrary points on a plane.
* @param lightX, lightY, lightZ The vector of the direction of light.(Not necessary to be normalized.)
* @return this
*/
dropShadowDirectionally(normX: any, normY: any, normZ: any, planeX: any, planeY: any, planeZ: any, lightX: any, lightY: any, lightZ: any): this;
makeRotationFromQuaternion(q: any): this;
compose(position: Vector3, quaternion: Quaternion, scale: Vector3): this;
decompose(position: any, quaternion: any, scale: any): this;
determinant(): number;
extractRotation(m: any): this;
}
export class Camera extends Object3D {
worldMatrixInverse: Matrix4;
projectionMatrix: Matrix4;
projectionMatrixInverse: Matrix4;
constructor();
/**
* 重写
* @param recursive
*/
clone(): Camera;
copy(source: any, recursive?: any): this;
getWorldDirection(target: Vector3): Vector3;
updateWorldMatrix(): void;
}
export class PerspectiveCamera extends Camera {
fov: number;
aspect: number;
near: number;
far: number;
zoom: number;
focus: number;
/**
*
* @param fov 张角
* @param aspect 长宽比例width/height
* @param near 最近近距离
* @param far 最远远距离
*/
constructor(fov?: number, aspect?: number, near?: number, far?: number);
set(fov?: number, aspect?: number, near?: number, far?: number): void;
copy(source: PerspectiveCamera, recursive?: boolean): this;
/**
* 更新
*/
updateProjectionMatrix(): void;
}
export class BaseShader extends GLShader {
/**
* 作为该着色器的标识
*/
_glShaderKey: string;
constructor(gl: WebGLRenderingContext);
}
export enum shaderReplaceStr {
POINT_LIGHTS_NUM = "POINT_LIGHTS_NUM",
DIR_LIGHTS_NUM = "DIR_LIGHTS_NUM"
}
export class LightShader extends GLShader {
/**
* 作为该着色器的标识
*/
_glShaderKey: string;
constructor(gl: WebGLRenderingContext, pointLightsNum?: number, dirLightsNum?: number);
}
export enum RenderSideType {
/**
* 正面才渲染,逆时针顶点
*/
FrontSide = 0,
/**
* 反面才渲染,顺时针顶点顺序
*/
BackSide = 1,
/**
* 两面都渲染
*/
DoubleSide = 2
}
export class BaseMaterial extends HashObject {
/**
* 十六进制 hex2rgb ,转成0到1的数组
*/
private _color;
private _colorArr;
color: number;
readonly colorArr: Float32Array;
/**
* 透明度0到1
*/
alpha: number;
/**
* 纹理贴图,默认白图
*/
map: Texture;
/**
* 是否用线框形式绘制
*/
wireframe: boolean;
side: RenderSideType;
/**
* 是否光照影响
*/
_lightAffect: boolean;
constructor(parameters?: any);
destroy(): void;
}
export class D3Renderer extends ObjectRenderer {
/**
* 赋值的相机,需要里面的worldMatrixInverse和projectionMatrix
*/
camera: Camera;
/**
* 灯光数据,用来初始化着色器和着色器传值
*/
lightsConfig: LightsConfig;
private curLightkey;
constructor(renderer: WebglRenderer);
onContextChange(): void;
start(): void;
stop(): void;
private meshes;
render(obj: Mesh3D): void;
flush(): void;
private packGeometry;
}
export class Light extends Object3D {
intensity: number;
private _color;
private _colorArr;
private _colorVec3;
color: number;
readonly colorArr: Float32Array;
readonly colorVec3: Vector3;
/**
*
* @param color rgb三分量的矢量,每个分量0到1,颜色方面后续优化
* @param intensity 光照强度 0到1 ,直接影响颜色值,不进uniform
*/
constructor(color: number, intensity?: number);
copy(light: Light): this;
}
export class PointLight extends Light {
distance: number;
decay: number;
/**
*
* @param color 颜色值,0到1的矢量
* @param intensity 强度
* @param distance 最大影响距离
* @param decay 衰减系数,//多试试2
*/
constructor(color: number, intensity: number, distance?: number, decay?: number);
power: number;
copy(pointLight: PointLight): this;
}
export class DirectionalLight extends Light {
/**
* 目标对象
*/
target: Object3D;
constructor(color: number, intensity: number);
copy(directionalLight: DirectionalLight): this;
}
export class Vector2 {
x: number;
y: number;
constructor(x?: number, y?: number);
set(x: number, y: number): this;
copy(v: Vector2): this;
clone(): Vector2;
add(v: any): this;
addScalar(s: any): this;
addVectors(a: any, b: any): this;
addScaledVector(v: any, s: any): this;
sub(v: any): this;
subScalar(s: any): this;
subVectors(a: any, b: any): this;
multiply(v: any): this;
multiplyScalar(scalar: any): this;
divide(v: any): this;
divideScalar(scalar: any): this;
applyMatrix3(m: any): this;
dot(v: any): number;
cross(v: any): number;
lengthSq(): number;
length(): number;
manhattanLength(): number;
normalize(): this;
angle(): number;
distanceTo(v: any): number;
distanceToSquared(v: any): number;
manhattanDistanceTo(v: any): number;
setLength(length: any): this;
lerp(v: any, alpha: any): this;
lerpVectors(v1: any, v2: any, alpha: any): this;
equals(v: any): boolean;
fromArray(array: any, offset: any): this;
toArray(array?: any[], offset?: number): any[];
}
export class Scene3D extends Object3D {
mouseEnable: boolean;
private _localID;
private _viewX;
viewX: number;
private _viewY;
viewY: number;
private _viewWidth;
viewWidth: number;
private _viewHeight;
viewHeight: number;
/**
* 父级是2d元素,用于修改视窗位置
*/
parent: any;
visible: boolean;
/**
* 相机
*/
camera: Camera;
constructor();
updateTransform(): void;
renderWebGL(renderer: WebglRenderer): void;
getLightConfig(con?: Object3D, arr?: LightsConfig): LightsConfig;
/**
* 点击事件,只算场景的先,待mesh等写完所有2d包围盒再说,将几何转成2d的点后,根据索引的所有三角面计算是否选中
* @param globalPoint
* @param isMouseEvent
*/
hitTestPoint(globalPoint: Point, isMouseEvent?: boolean): this;
/**
* 为了兼容stage里鼠标事件需要计算localX和localY
* @param vector
*/
globalToLocal(vector: Vector3): Vector3;
setOrbitControl(): void;
}
export interface LightsConfig {
pointLights: PointLightConfig[];
directionalLights: DirectionalLightConfig[];
ambientLightColor: number[];
}
export {};
export enum RotationOrders {
XYZ = "XYZ",
YZX = "YZX",
ZXY = "ZXY",
XZY = "XZY",
YXZ = "YXZ",
ZYX = "ZYX"
}
export class Euler {
private _x;
private _y;
private _z;
private _order;
constructor(_x?: number, _y?: number, _z?: number, _order?: RotationOrders);
x: number;
y: number;
z: number;
order: RotationOrders;
set(x: any, y: any, z: any, order: any): this;
clone(): Euler;
copy(euler: Euler): this;
setFromRotationMatrix(m: Matrix4, order: RotationOrders, update: any): this;
setFromQuaternion: (q: Quaternion, order: any, update: any) => any;
setFromVector3(v: any, order: RotationOrders): this;
reorder: (newOrder: any) => any;
equals(euler: any): boolean;
fromArray(array: any): this;
toArray(array: any, offset: any): any;
toVector3(optionalResult: any): any;
onChange(callback: any): this;
onChangeCallback(): void;
}
export class Object3D extends EventDispatcher {
static DefaultUp: Vector3;
/**
* 名字
*/
name: string;
/**
* 是否可见
*/
visible: boolean;
/**
* 场景
*/
scene: Scene3D;
/**
* 子级
*/
children: Object3D[];
/**
* 父级
*/
parent: Object3D;
/**
* 世界矩阵
*/
_worldMatrix: Matrix4;
/**
* 本地矩阵
*/
_localMatrix: Matrix4;
up: Vector3;
position: Vector3;
scale: Vector3;
rotation: Euler;
quaternion: Quaternion;
constructor();
addChild<T extends Object3D>(object: T): T;
addChildAt<T extends Object3D>(child: T, index: number): T;
removeChild<T extends Object3D>(object: T): T;
/**
* FYGE. Event得加上属性REMOVED_FROM_SCENE,ADDED_TO_SCENE
* @param type
*/
private _onDispatchBubbledEvent;
clone(recursive?: boolean): Object3D;
copy(source: Object3D, recursive?: boolean): this;
lookAt(x: number, y: number, z: number): void;
localToGlobal(vector: Vector3): Vector3;
globalToLocal(vector: Vector3): Vector3;
updateLocalMatrix(): void;
updateWorldMatrix(updateParents?: boolean, updateChildren?: boolean): void;
/**
* 统一更新方法,子类可重写,基类用于派发监听事件
*/
update(): void;
/**
* 通过名字获取子级
* @param name
* @param isOnlyOne
* @param isRecursive
*/
getChildByName(name: string | RegExp, isOnlyOne?: boolean, isRecursive?: boolean): any;
/**
*
* @param rex
* @param root
* @param isOnlyOne
* @param isRecursive
* @param resultList
*/
private static _getElementsByName;
/**
* 渲染绘制
*/
render(renderer: any): void;
/**
* 子级重写,自身的渲染方式
*/
protected _render(renderer: any): void;
destroy(): void;
/**
* 位置信息
*/
x: number;
y: number;
z: number;
/**
* 缩放信息
*/
scaleX: number;
scaleY: number;
scaleZ: number;
/**
* 旋转信息,角度制度
*/
/**
* 角度制
*/
rotationX: number;
/**
* 旋转信息,角度制度
*/
/**
* 角度制
*/
rotationY: number;
/**
* 旋转信息,角度制度
*/
/**
* 角度制
*/
rotationZ: number;
}
export class Geometry extends HashObject {
/**
* 顶点坐标3,颜色3,uv2,法线3
*/
_vertByteSize: number;
_vertices: Float32Array | number[];
_indices: Uint16Array | number[];
_colors: Float32Array | number[];
_uvs: Float32Array | number[];
_normals: Float32Array | number[];
/**
* 为了不同渲染器上下文对应自己的vao,不管program吧,可能不同着色器程序,带的attr可能不一样,
* 在3d的插件上处理
* 建vao,添加attr属性
* 激活绑定vao
* 绑定buffer,
* 上传buffer数据
* 绘制
*
*/
_glVaoBuffer: {
[key: number]: VaoBufferInt;
};
/**
* 记录顶点数据用
*/
_attrBuffer: BatchBuffer;
/**
* 索引数据
*/
/**
*
* @param vertices
* @param indices
* @param colors
* @param uvs
*/
constructor(vertices: Float32Array | number[], indices?: Uint16Array | number[], normals?: Float32Array | number[], colors?: Float32Array | number[], uvs?: Float32Array | number[]);
destroy(): void;
}
export {};
export class Mesh3D extends Object3D {
geometry: Geometry;
material: BaseMaterial;
constructor(geometry: Geometry, material: BaseMaterial);
_render(renderer: any): void;
}
export class SphereGeometry extends Geometry {
constructor(radius?: number, widthSegments?: number, heightSegments?: number, phiStart?: number, phiLength?: number, thetaStart?: number, thetaLength?: number);
}
export class BoxGeometry extends Geometry {
constructor(width?: number, height?: number, depth?: number, widthSegments?: number, heightSegments?: number, depthSegments?: number);
}
export class PlaneGeometry extends Geometry {
constructor(width?: number, height?: number, widthSegments?: number, heightSegments?: number);
}
export class LightMaterial extends BaseMaterial {
constructor(parameters?: any);
}
export class AmbientLight extends Light {
constructor(color: number, intensity: number);
}
export class AxesHelper extends Mesh3D {
constructor(size?: number);
}
export class GridHelper extends Mesh3D {
constructor(size?: number, divisions?: number, color1?: number, color2?: number);
}
export var Stats: (canvasId: any) => {
begin: () => void;
end: () => number;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -273,6 +273,7 @@ export class Stage extends Container {
* @private
*/
onMouseEvent(e: any): void {
e.preventDefault();
let s: Stage = this;
//检查mouse或touch事件是否有,如果有的话,就触发事件函数
if (EventDispatcher._totalMEC > 0) {
......
......@@ -78,7 +78,7 @@ export class Loader extends EventDispatcher {
* @param callback
* @param url
*/
loadJson(callback, url) {
loadJson(callback: (s: boolean, res: any) => void, url: string) {
//@ts-ignore ,正式环境不能使用request,走downloadFile
// my.request({
// url: url,
......@@ -97,6 +97,14 @@ export class Loader extends EventDispatcher {
this.tbLoad(callback, url, "utf8")
return
}
this.loadRawWeb(callback, url, "json")
}
loadRawWeb(
callback: (s: boolean, res: any) => void,
url: string,
type: 'text' | 'json' | 'arraybuffer' = "json"
) {
//每次都要new
let _req;
if (window["XMLHttpRequest"]) {
......@@ -108,7 +116,7 @@ export class Loader extends EventDispatcher {
}
if (_req != null) {
_req.open("GET", url, true);
_req.responseType = "json";
_req.responseType = type;
_req.send();
_req.onreadystatechange = () => {
if (_req.readyState == 4 && _req.status == 200) {
......@@ -178,7 +186,7 @@ export class Loader extends EventDispatcher {
* @param callback
* @param url
*/
private tbLoad(
tbLoad(
callback: (s: boolean, res?: any) => void,
url: string,
type: "utf8" | "ArrayBuffer" = "ArrayBuffer"
......
import { EventDispatcher } from "../2d/events";
import { GlobalLoader } from "../2d/loader";
import { rgb2hex } from "../2d/utils";
import { DirectionalLight, PointLight } from ".";
/* BINARY EXTENSION */
var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
var BINARY_EXTENSION_HEADER_LENGTH = 12;
var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
/*********************************/
/********** EXTENSIONS ***********/
/*********************************/
var EXTENSIONS = {
KHR_BINARY_GLTF: 'KHR_binary_glTF',
KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
};
class GLTFLoader extends EventDispatcher {
constructor() {//anonymous
super();
}
load(
url: string,
onLoad: (gltf) => void,
onError: (err: any) => void
) {
var scope = this;
let callback = (s: boolean, res: any) => {
if (s) {//得到二进制数据
try {
scope.parse(res, function (gltf) {
onLoad(gltf);
}, onError);
} catch (e) {
onError(e);
}
} else {
onError && onError(res)
}
}
//@ts-ignore
if (my) {
GlobalLoader.tbLoad(callback, url, "ArrayBuffer")
} else {
GlobalLoader.loadRawWeb(callback, url, "arraybuffer")
}
}
parse(data: any, onLoad: (res: any) => void, onError: (err: any) => void) {
var content: string;
var extensions = {};
if (typeof data === 'string') {
content = data;
} else {
var magic = decodeText(new Uint8Array(data, 0, 4));
if (magic === BINARY_EXTENSION_HEADER_MAGIC) {
try {
extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data);
} catch (error) {
if (onError) onError(error);
return;
}
content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content;
} else {
content = decodeText(new Uint8Array(data));
}
}
var json = JSON.parse(content);
console.log(json)
if (json.asset === undefined || json.asset.version[0] < 2) {
onError && onError("版本格式有问题")
return;
}
var parser = new GLTFParser(json, extensions);
parser.parse(function (scene, scenes, cameras, animations, json) {
var glTF = {
scene: scene,
scenes: scenes,
cameras: cameras,
animations: animations,
asset: json.asset,
parser: parser,
userData: {}
};
// addUnknownExtensionsToUserData(extensions, glTF, json);
onLoad(glTF);
}, onError);
}
}
THREE.GLTFLoader = (function () {
function GLTFRegistry() {
var objects = {};
return {
get: function (key) {
return objects[key];
},
add: function (key, object) {
objects[key] = object;
},
remove: function (key) {
delete objects[key];
},
removeAll: function () {
objects = {};
}
};
}
/*********************************/
/********** INTERPOLATION ********/
/*********************************/
// Spline Interpolation
// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
function GLTFCubicSplineInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {
THREE.Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);
}
GLTFCubicSplineInterpolant.prototype = Object.create(THREE.Interpolant.prototype);
GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant;
GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function (index) {
// Copies a sample value to the result buffer. See description of glTF
// CUBICSPLINE values layout in interpolate_() function below.
var result = this.resultBuffer,
values = this.sampleValues,
valueSize = this.valueSize,
offset = index * valueSize * 3 + valueSize;
for (var i = 0; i !== valueSize; i++) {
result[i] = values[offset + i];
}
return result;
};
GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
GLTFCubicSplineInterpolant.prototype.interpolate_ = function (i1, t0, t, t1) {
var result = this.resultBuffer;
var values = this.sampleValues;
var stride = this.valueSize;
var stride2 = stride * 2;
var stride3 = stride * 3;
var td = t1 - t0;
var p = (t - t0) / td;
var pp = p * p;
var ppp = pp * p;
var offset1 = i1 * stride3;
var offset0 = offset1 - stride3;
var s0 = 2 * ppp - 3 * pp + 1;
var s1 = ppp - 2 * pp + p;
var s2 = - 2 * ppp + 3 * pp;
var s3 = ppp - pp;
// Layout of keyframe output values for CUBICSPLINE animations:
// [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
for (var i = 0; i !== stride; i++) {
var p0 = values[offset0 + i + stride]; // splineVertex_k
var m0 = values[offset0 + i + stride2] * td; // outTangent_k * (t_k+1 - t_k)
var p1 = values[offset1 + i + stride]; // splineVertex_k+1
var m1 = values[offset1 + i] * td; // inTangent_k+1 * (t_k+1 - t_k)
result[i] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;
}
return result;
};
/*********************************/
/********** INTERNALS ************/
/*********************************/
/* CONSTANTS */
var WEBGL_CONSTANTS = {
FLOAT: 5126,
//FLOAT_MAT2: 35674,
FLOAT_MAT3: 35675,
FLOAT_MAT4: 35676,
FLOAT_VEC2: 35664,
FLOAT_VEC3: 35665,
FLOAT_VEC4: 35666,
LINEAR: 9729,
REPEAT: 10497,
SAMPLER_2D: 35678,
POINTS: 0,
LINES: 1,
LINE_LOOP: 2,
LINE_STRIP: 3,
TRIANGLES: 4,
TRIANGLE_STRIP: 5,
TRIANGLE_FAN: 6,
UNSIGNED_BYTE: 5121,
UNSIGNED_SHORT: 5123
};
var WEBGL_COMPONENT_TYPES = {
5120: Int8Array,
5121: Uint8Array,
5122: Int16Array,
5123: Uint16Array,
5125: Uint32Array,
5126: Float32Array
};
var WEBGL_TYPE_SIZES = {
'SCALAR': 1,
'VEC2': 2,
'VEC3': 3,
'VEC4': 4,
'MAT2': 4,
'MAT3': 9,
'MAT4': 16
};
var ATTRIBUTES = {
POSITION: 'position',
NORMAL: 'normal',
TEXCOORD_0: 'uv',
TEXCOORD0: 'uv', // deprecated
TEXCOORD: 'uv', // deprecated
TEXCOORD_1: 'uv2',
COLOR_0: 'color',
COLOR0: 'color', // deprecated
COLOR: 'color', // deprecated
WEIGHTS_0: 'skinWeight',
WEIGHT: 'skinWeight', // deprecated
JOINTS_0: 'skinIndex',
JOINT: 'skinIndex' // deprecated
};
var PATH_PROPERTIES = {
scale: 'scale',
translation: 'position',
rotation: 'quaternion',
weights: 'morphTargetInfluences'
};
var INTERPOLATION = {
CUBICSPLINE: THREE.InterpolateSmooth, // We use custom interpolation GLTFCubicSplineInterpolation for CUBICSPLINE.
// KeyframeTrack.optimize() can't handle glTF Cubic Spline output values layout,
// using THREE.InterpolateSmooth for KeyframeTrack instantiation to prevent optimization.
// See KeyframeTrack.optimize() for the detail.
LINEAR: THREE.InterpolateLinear,
STEP: THREE.InterpolateDiscrete
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
*/
function createDefaultMaterial() {
return new THREE.MeshStandardMaterial({
color: 0xFFFFFF,
emissive: 0x000000,
metalness: 1,
roughness: 1,
transparent: false,
depthTest: true,
side: THREE.FrontSide
});
}
function addUnknownExtensionsToUserData(knownExtensions, object, objectDef) {
// Add unknown glTF extensions to an object's userData.
for (var name in objectDef.extensions) {
if (knownExtensions[name] === undefined) {
object.userData.gltfExtensions = object.userData.gltfExtensions || {};
object.userData.gltfExtensions[name] = objectDef.extensions[name];
}
}
}
/**
* @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry} object
* @param {GLTF.definition} def
*/
function assignExtrasToUserData(object, gltfDef) {
if (gltfDef.extras !== undefined) {
if (typeof gltfDef.extras === 'object') {
object.userData = gltfDef.extras;
} else {
console.warn('THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras);
}
}
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
*
* @param {THREE.BufferGeometry} geometry
* @param {Array<GLTF.Target>} targets
* @param {Array<THREE.BufferAttribute>} accessors
*/
function addMorphTargets(geometry, targets, accessors) {
var hasMorphPosition = false;
var hasMorphNormal = false;
for (var i = 0, il = targets.length; i < il; i++) {
var target = targets[i];
if (target.POSITION !== undefined) hasMorphPosition = true;
if (target.NORMAL !== undefined) hasMorphNormal = true;
if (hasMorphPosition && hasMorphNormal) break;
}
if (!hasMorphPosition && !hasMorphNormal) return;
var morphPositions = [];
var morphNormals = [];
for (var i = 0, il = targets.length; i < il; i++) {
var target = targets[i];
var attributeName = 'morphTarget' + i;
if (hasMorphPosition) {
// Three.js morph position is absolute value. The formula is
// basePosition
// + weight0 * ( morphPosition0 - basePosition )
// + weight1 * ( morphPosition1 - basePosition )
// ...
// while the glTF one is relative
// basePosition
// + weight0 * glTFmorphPosition0
// + weight1 * glTFmorphPosition1
// ...
// then we need to convert from relative to absolute here.
if (target.POSITION !== undefined) {
// Cloning not to pollute original accessor
var positionAttribute = cloneBufferAttribute(accessors[target.POSITION]);
positionAttribute.name = attributeName;
var position = geometry.attributes.position;
for (var j = 0, jl = positionAttribute.count; j < jl; j++) {
positionAttribute.setXYZ(
j,
positionAttribute.getX(j) + position.getX(j),
positionAttribute.getY(j) + position.getY(j),
positionAttribute.getZ(j) + position.getZ(j)
);
}
} else {
positionAttribute = geometry.attributes.position;
}
morphPositions.push(positionAttribute);
}
if (hasMorphNormal) {
// see target.POSITION's comment
var normalAttribute;
if (target.NORMAL !== undefined) {
var normalAttribute = cloneBufferAttribute(accessors[target.NORMAL]);
normalAttribute.name = attributeName;
var normal = geometry.attributes.normal;
for (var j = 0, jl = normalAttribute.count; j < jl; j++) {
normalAttribute.setXYZ(
j,
normalAttribute.getX(j) + normal.getX(j),
normalAttribute.getY(j) + normal.getY(j),
normalAttribute.getZ(j) + normal.getZ(j)
);
}
} else {
normalAttribute = geometry.attributes.normal;
}
morphNormals.push(normalAttribute);
}
}
if (hasMorphPosition) geometry.morphAttributes.position = morphPositions;
if (hasMorphNormal) geometry.morphAttributes.normal = morphNormals;
}
/**
* @param {THREE.Mesh} mesh
* @param {GLTF.Mesh} meshDef
*/
function updateMorphTargets(mesh, meshDef) {
mesh.updateMorphTargets();
if (meshDef.weights !== undefined) {
for (var i = 0, il = meshDef.weights.length; i < il; i++) {
mesh.morphTargetInfluences[i] = meshDef.weights[i];
}
}
// .extras has user-defined data, so check that .extras.targetNames is an array.
if (meshDef.extras && Array.isArray(meshDef.extras.targetNames)) {
var targetNames = meshDef.extras.targetNames;
if (mesh.morphTargetInfluences.length === targetNames.length) {
mesh.morphTargetDictionary = {};
for (var i = 0, il = targetNames.length; i < il; i++) {
mesh.morphTargetDictionary[targetNames[i]] = i;
}
} else {
console.warn('THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.');
}
}
}
function isPrimitiveEqual(a, b) {
if (a.indices !== b.indices) {
return false;
}
return isObjectEqual(a.attributes, b.attributes);
}
function isObjectEqual(a, b) {
if (Object.keys(a).length !== Object.keys(b).length) return false;
for (var key in a) {
if (a[key] !== b[key]) return false;
}
return true;
}
function isArrayEqual(a, b) {
if (a.length !== b.length) return false;
for (var i = 0, il = a.length; i < il; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
function getCachedGeometry(cache, newPrimitive) {
for (var i = 0, il = cache.length; i < il; i++) {
var cached = cache[i];
if (isPrimitiveEqual(cached.primitive, newPrimitive)) return cached.promise;
}
return null;
}
function getCachedCombinedGeometry(cache, geometries) {
for (var i = 0, il = cache.length; i < il; i++) {
var cached = cache[i];
if (isArrayEqual(geometries, cached.baseGeometries)) return cached.geometry;
}
return null;
}
function getCachedMultiPassGeometry(cache, geometry, primitives) {
for (var i = 0, il = cache.length; i < il; i++) {
var cached = cache[i];
if (geometry === cached.baseGeometry && isArrayEqual(primitives, cached.primitives)) return cached.geometry;
}
return null;
}
function cloneBufferAttribute(attribute) {
if (attribute.isInterleavedBufferAttribute) {
var count = attribute.count;
var itemSize = attribute.itemSize;
var array = attribute.array.slice(0, count * itemSize);
for (var i = 0; i < count; ++i) {
array[i] = attribute.getX(i);
if (itemSize >= 2) array[i + 1] = attribute.getY(i);
if (itemSize >= 3) array[i + 2] = attribute.getZ(i);
if (itemSize >= 4) array[i + 3] = attribute.getW(i);
}
return new THREE.BufferAttribute(array, itemSize, attribute.normalized);
}
return attribute.clone();
}
/**
* Checks if we can build a single Mesh with MultiMaterial from multiple primitives.
* Returns true if all primitives use the same attributes/morphAttributes/mode
* and also have index. Otherwise returns false.
*
* @param {Array<GLTF.Primitive>} primitives
* @return {Boolean}
*/
function isMultiPassGeometry(primitives) {
if (primitives.length < 2) return false;
var primitive0 = primitives[0];
var targets0 = primitive0.targets || [];
if (primitive0.indices === undefined) return false;
for (var i = 1, il = primitives.length; i < il; i++) {
var primitive = primitives[i];
if (primitive0.mode !== primitive.mode) return false;
if (primitive.indices === undefined) return false;
if (!isObjectEqual(primitive0.attributes, primitive.attributes)) return false;
var targets = primitive.targets || [];
if (targets0.length !== targets.length) return false;
for (var j = 0, jl = targets0.length; j < jl; j++) {
if (!isObjectEqual(targets0[j], targets[j])) return false;
}
}
return true;
}
/* GLTF PARSER */
function GLTFParser(json, extensions, options) {
this.json = json || {};
this.extensions = extensions || {};
this.options = options || {};
// loader object cache
this.cache = new GLTFRegistry();
// BufferGeometry caching
this.primitiveCache = [];
this.multiplePrimitivesCache = [];
this.multiPassGeometryCache = [];
this.textureLoader = new THREE.TextureLoader(this.options.manager);
this.textureLoader.setCrossOrigin(this.options.crossOrigin);
this.fileLoader = new THREE.FileLoader(this.options.manager);
this.fileLoader.setResponseType('arraybuffer');
}
GLTFParser.prototype.parse = function (onLoad, onError) {
var json = this.json;
// Clear the loader cache
this.cache.removeAll();
// Mark the special nodes/meshes in json for efficient parse
this.markDefs();
// Fire the callback on complete
this.getMultiDependencies([
'scene',
'animation',
'camera'
]).then(function (dependencies) {
var scenes = dependencies.scenes || [];
var scene = scenes[json.scene || 0];
var animations = dependencies.animations || [];
var cameras = dependencies.cameras || [];
onLoad(scene, scenes, cameras, animations, json);
}).catch(onError);
};
/**
* Marks the special nodes/meshes in json for efficient parse.
*/
GLTFParser.prototype.markDefs = function () {
var nodeDefs = this.json.nodes || [];
var skinDefs = this.json.skins || [];
var meshDefs = this.json.meshes || [];
var meshReferences = {};
var meshUses = {};
// Nothing in the node definition indicates whether it is a Bone or an
// Object3D. Use the skins' joint references to mark bones.
for (var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++) {
var joints = skinDefs[skinIndex].joints;
for (var i = 0, il = joints.length; i < il; i++) {
nodeDefs[joints[i]].isBone = true;
}
}
// Meshes can (and should) be reused by multiple nodes in a glTF asset. To
// avoid having more than one THREE.Mesh with the same name, count
// references and rename instances below.
//
// Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
for (var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) {
var nodeDef = nodeDefs[nodeIndex];
if (nodeDef.mesh !== undefined) {
if (meshReferences[nodeDef.mesh] === undefined) {
meshReferences[nodeDef.mesh] = meshUses[nodeDef.mesh] = 0;
}
meshReferences[nodeDef.mesh]++;
// Nothing in the mesh definition indicates whether it is
// a SkinnedMesh or Mesh. Use the node's mesh reference
// to mark SkinnedMesh if node has skin.
if (nodeDef.skin !== undefined) {
meshDefs[nodeDef.mesh].isSkinnedMesh = true;
}
}
}
this.json.meshReferences = meshReferences;
this.json.meshUses = meshUses;
};
/**
* Requests the specified dependency asynchronously, with caching.
* @param {string} type
* @param {number} index
* @return {Promise<Object>}
*/
GLTFParser.prototype.getDependency = function (type, index) {
var cacheKey = type + ':' + index;
var dependency = this.cache.get(cacheKey);
if (!dependency) {
switch (type) {
case 'scene':
dependency = this.loadScene(index);
break;
case 'node':
dependency = this.loadNode(index);
break;
case 'mesh':
dependency = this.loadMesh(index);
break;
case 'accessor':
dependency = this.loadAccessor(index);
break;
case 'bufferView':
dependency = this.loadBufferView(index);
break;
case 'buffer':
dependency = this.loadBuffer(index);
break;
case 'material':
dependency = this.loadMaterial(index);
break;
case 'texture':
dependency = this.loadTexture(index);
break;
case 'skin':
dependency = this.loadSkin(index);
break;
case 'animation':
dependency = this.loadAnimation(index);
break;
case 'camera':
dependency = this.loadCamera(index);
break;
default:
throw new Error('Unknown type: ' + type);
}
this.cache.add(cacheKey, dependency);
}
return dependency;
};
/**
* Requests all dependencies of the specified type asynchronously, with caching.
* @param {string} type
* @return {Promise<Array<Object>>}
*/
GLTFParser.prototype.getDependencies = function (type) {
var dependencies = this.cache.get(type);
if (!dependencies) {
var parser = this;
var defs = this.json[type + (type === 'mesh' ? 'es' : 's')] || [];
dependencies = Promise.all(defs.map(function (def, index) {
return parser.getDependency(type, index);
}));
this.cache.add(type, dependencies);
}
return dependencies;
};
/**
* Requests all multiple dependencies of the specified types asynchronously, with caching.
* @param {Array<string>} types
* @return {Promise<Object<Array<Object>>>}
*/
GLTFParser.prototype.getMultiDependencies = function (types) {
var results = {};
var pendings = [];
for (var i = 0, il = types.length; i < il; i++) {
var type = types[i];
var value = this.getDependencies(type);
value = value.then(function (key, value) {
results[key] = value;
}.bind(this, type + (type === 'mesh' ? 'es' : 's')));
pendings.push(value);
}
return Promise.all(pendings).then(function () {
return results;
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
* @param {number} bufferIndex
* @return {Promise<ArrayBuffer>}
*/
GLTFParser.prototype.loadBuffer = function (bufferIndex) {
var bufferDef = this.json.buffers[bufferIndex];
var loader = this.fileLoader;
if (bufferDef.type && bufferDef.type !== 'arraybuffer') {
throw new Error('THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.');
}
// If present, GLB container is required to be the first buffer.
if (bufferDef.uri === undefined && bufferIndex === 0) {
return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body);
}
var options = this.options;
return new Promise(function (resolve, reject) {
loader.load(resolveURL(bufferDef.uri, options.path), resolve, undefined, function () {
reject(new Error('THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".'));
});
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
* @param {number} bufferViewIndex
* @return {Promise<ArrayBuffer>}
*/
GLTFParser.prototype.loadBufferView = function (bufferViewIndex) {
var bufferViewDef = this.json.bufferViews[bufferViewIndex];
return this.getDependency('buffer', bufferViewDef.buffer).then(function (buffer) {
var byteLength = bufferViewDef.byteLength || 0;
var byteOffset = bufferViewDef.byteOffset || 0;
return buffer.slice(byteOffset, byteOffset + byteLength);
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
* @param {number} accessorIndex
* @return {Promise<THREE.BufferAttribute|THREE.InterleavedBufferAttribute>}
*/
GLTFParser.prototype.loadAccessor = function (accessorIndex) {
var parser = this;
var json = this.json;
var accessorDef = this.json.accessors[accessorIndex];
if (accessorDef.bufferView === undefined && accessorDef.sparse === undefined) {
// Ignore empty accessors, which may be used to declare runtime
// information about attributes coming from another source (e.g. Draco
// compression extension).
return null;
}
var pendingBufferViews = [];
if (accessorDef.bufferView !== undefined) {
pendingBufferViews.push(this.getDependency('bufferView', accessorDef.bufferView));
} else {
pendingBufferViews.push(null);
}
if (accessorDef.sparse !== undefined) {
pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.indices.bufferView));
pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.values.bufferView));
}
return Promise.all(pendingBufferViews).then(function (bufferViews) {
var bufferView = bufferViews[0];
var itemSize = WEBGL_TYPE_SIZES[accessorDef.type];
var TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType];
// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
var elementBytes = TypedArray.BYTES_PER_ELEMENT;
var itemBytes = elementBytes * itemSize;
var byteOffset = accessorDef.byteOffset || 0;
var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[accessorDef.bufferView].byteStride : undefined;
var normalized = accessorDef.normalized === true;
var array, bufferAttribute;
// The buffer is not interleaved if the stride is the item size in bytes.
if (byteStride && byteStride !== itemBytes) {
var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType;
var ib = parser.cache.get(ibCacheKey);
if (!ib) {
// Use the full buffer if it's interleaved.
array = new TypedArray(bufferView);
// Integer parameters to IB/IBA are in array elements, not bytes.
ib = new THREE.InterleavedBuffer(array, byteStride / elementBytes);
parser.cache.add(ibCacheKey, ib);
}
bufferAttribute = new THREE.InterleavedBufferAttribute(ib, itemSize, byteOffset / elementBytes, normalized);
} else {
if (bufferView === null) {
array = new TypedArray(accessorDef.count * itemSize);
} else {
array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize);
}
bufferAttribute = new THREE.BufferAttribute(array, itemSize, normalized);
}
// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
if (accessorDef.sparse !== undefined) {
var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
var TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType];
var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
var sparseIndices = new TypedArrayIndices(bufferViews[1], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices);
var sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize);
if (bufferView !== null) {
// Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
bufferAttribute.setArray(bufferAttribute.array.slice());
}
for (var i = 0, il = sparseIndices.length; i < il; i++) {
var index = sparseIndices[i];
bufferAttribute.setX(index, sparseValues[i * itemSize]);
if (itemSize >= 2) bufferAttribute.setY(index, sparseValues[i * itemSize + 1]);
if (itemSize >= 3) bufferAttribute.setZ(index, sparseValues[i * itemSize + 2]);
if (itemSize >= 4) bufferAttribute.setW(index, sparseValues[i * itemSize + 3]);
if (itemSize >= 5) throw new Error('THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.');
}
}
return bufferAttribute;
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
* @param {number} textureIndex
* @return {Promise<THREE.Texture>}
*/
GLTFParser.prototype.loadTexture = function (textureIndex) {
var parser = this;
var json = this.json;
var options = this.options;
var textureLoader = this.textureLoader;
var URL = window.URL || window.webkitURL;
var textureDef = json.textures[textureIndex];
var textureExtensions = textureDef.extensions || {};
var source;
if (textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]) {
source = json.images[textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS].source];
} else {
source = json.images[textureDef.source];
}
var sourceURI = source.uri;
var isObjectURL = false;
if (source.bufferView !== undefined) {
// Load binary image data from bufferView, if provided.
sourceURI = parser.getDependency('bufferView', source.bufferView).then(function (bufferView) {
isObjectURL = true;
var blob = new Blob([bufferView], { type: source.mimeType });
sourceURI = URL.createObjectURL(blob);
return sourceURI;
});
}
return Promise.resolve(sourceURI).then(function (sourceURI) {
// Load Texture resource.
var loader = THREE.Loader.Handlers.get(sourceURI);
if (!loader) {
loader = textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]
? parser.extensions[EXTENSIONS.MSFT_TEXTURE_DDS].ddsLoader
: textureLoader;
}
return new Promise(function (resolve, reject) {
loader.load(resolveURL(sourceURI, options.path), resolve, undefined, reject);
});
}).then(function (texture) {
// Clean up resources and configure Texture.
if (isObjectURL === true) {
URL.revokeObjectURL(sourceURI);
}
texture.flipY = false;
if (textureDef.name !== undefined) texture.name = textureDef.name;
// Ignore unknown mime types, like DDS files.
// if (source.mimeType in MIME_TYPE_FORMATS) {
// texture.format = MIME_TYPE_FORMATS[source.mimeType];
// }
var samplers = json.samplers || {};
var sampler = samplers[textureDef.sampler] || {};
// texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || THREE.LinearFilter;
// texture.minFilter = WEBGL_FILTERS[sampler.minFilter] || THREE.LinearMipMapLinearFilter;
// texture.wrapS = WEBGL_WRAPPINGS[sampler.wrapS] || THREE.RepeatWrapping;
// texture.wrapT = WEBGL_WRAPPINGS[sampler.wrapT] || THREE.RepeatWrapping;
return texture;
});
};
/**
* Asynchronously assigns a texture to the given material parameters.
* @param {Object} materialParams
* @param {string} textureName
* @param {number} textureIndex
* @return {Promise}
*/
GLTFParser.prototype.assignTexture = function (materialParams, textureName, textureIndex) {
return this.getDependency('texture', textureIndex).then(function (texture) {
materialParams[textureName] = texture;
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
* @param {number} materialIndex
* @return {Promise<THREE.Material>}
*/
GLTFParser.prototype.loadMaterial = function (materialIndex) {
var parser = this;
var json = this.json;
var extensions = this.extensions;
var materialDef = json.materials[materialIndex];
var materialType;
var materialParams = {};
var materialExtensions = materialDef.extensions || {};
var pending = [];
if (materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]) {
var sgExtension = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS];
materialType = sgExtension.getMaterialType(materialDef);
pending.push(sgExtension.extendParams(materialParams, materialDef, parser));
} else if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {
var kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT];
materialType = kmuExtension.getMaterialType(materialDef);
pending.push(kmuExtension.extendParams(materialParams, materialDef, parser));
} else {
// Specification:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
materialType = THREE.MeshStandardMaterial;
var metallicRoughness = materialDef.pbrMetallicRoughness || {};
materialParams.color = new THREE.Color(1.0, 1.0, 1.0);
materialParams.opacity = 1.0;
if (Array.isArray(metallicRoughness.baseColorFactor)) {
var array = metallicRoughness.baseColorFactor;
materialParams.color.fromArray(array);
materialParams.opacity = array[3];
}
if (metallicRoughness.baseColorTexture !== undefined) {
pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture.index));
}
materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
if (metallicRoughness.metallicRoughnessTexture !== undefined) {
var textureIndex = metallicRoughness.metallicRoughnessTexture.index;
pending.push(parser.assignTexture(materialParams, 'metalnessMap', textureIndex));
pending.push(parser.assignTexture(materialParams, 'roughnessMap', textureIndex));
}
}
if (materialDef.doubleSided === true) {
materialParams.side = THREE.DoubleSide;
}
// var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
// if (alphaMode === ALPHA_MODES.BLEND) {
// materialParams.transparent = true;
// } else {
// materialParams.transparent = false;
// if (alphaMode === ALPHA_MODES.MASK) {
// materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
// }
// }
if (materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
pending.push(parser.assignTexture(materialParams, 'normalMap', materialDef.normalTexture.index));
materialParams.normalScale = new THREE.Vector2(1, 1);
if (materialDef.normalTexture.scale !== undefined) {
materialParams.normalScale.set(materialDef.normalTexture.scale, materialDef.normalTexture.scale);
}
}
if (materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
pending.push(parser.assignTexture(materialParams, 'aoMap', materialDef.occlusionTexture.index));
if (materialDef.occlusionTexture.strength !== undefined) {
materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
}
}
if (materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial) {
materialParams.emissive = new THREE.Color().fromArray(materialDef.emissiveFactor);
}
if (materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
pending.push(parser.assignTexture(materialParams, 'emissiveMap', materialDef.emissiveTexture.index));
}
return Promise.all(pending).then(function () {
var material;
if (materialType === THREE.ShaderMaterial) {
material = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].createMaterial(materialParams);
} else {
material = new materialType(materialParams);
}
if (materialDef.name !== undefined) material.name = materialDef.name;
// Normal map textures use OpenGL conventions:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture
if (material.normalScale) {
material.normalScale.y = - material.normalScale.y;
}
// baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
if (material.map) material.map.encoding = THREE.sRGBEncoding;
if (material.emissiveMap) material.emissiveMap.encoding = THREE.sRGBEncoding;
if (material.specularMap) material.specularMap.encoding = THREE.sRGBEncoding;
assignExtrasToUserData(material, materialDef);
if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef);
return material;
});
};
/**
* @param {THREE.BufferGeometry} geometry
* @param {GLTF.Primitive} primitiveDef
* @param {Array<THREE.BufferAttribute>} accessors
*/
function addPrimitiveAttributes(geometry, primitiveDef, accessors) {
var attributes = primitiveDef.attributes;
for (var gltfAttributeName in attributes) {
var threeAttributeName = ATTRIBUTES[gltfAttributeName];
var bufferAttribute = accessors[attributes[gltfAttributeName]];
// Skip attributes already provided by e.g. Draco extension.
if (!threeAttributeName) continue;
if (threeAttributeName in geometry.attributes) continue;
geometry.addAttribute(threeAttributeName, bufferAttribute);
}
if (primitiveDef.indices !== undefined && !geometry.index) {
geometry.setIndex(accessors[primitiveDef.indices]);
}
if (primitiveDef.targets !== undefined) {
addMorphTargets(geometry, primitiveDef.targets, accessors);
}
assignExtrasToUserData(geometry, primitiveDef);
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
*
* Creates BufferGeometries from primitives.
* If we can build a single BufferGeometry with .groups from multiple primitives, returns one BufferGeometry.
* Otherwise, returns BufferGeometries without .groups as many as primitives.
*
* @param {Array<Object>} primitives
* @return {Promise<Array<THREE.BufferGeometry>>}
*/
GLTFParser.prototype.loadGeometries = function (primitives) {
var parser = this;
var extensions = this.extensions;
var cache = this.primitiveCache;
var isMultiPass = isMultiPassGeometry(primitives);
var originalPrimitives;
if (isMultiPass) {
originalPrimitives = primitives; // save original primitives and use later
// We build a single BufferGeometry with .groups from multiple primitives
// because all primitives share the same attributes/morph/mode and have indices.
primitives = [primitives[0]];
// Sets .groups and combined indices to a geometry later in this method.
}
return this.getDependencies('accessor').then(function (accessors) {
var pending = [];
for (var i = 0, il = primitives.length; i < il; i++) {
var primitive = primitives[i];
// See if we've already created this geometry
var cached = getCachedGeometry(cache, primitive);
if (cached) {
// Use the cached geometry if it exists
pending.push(cached);
} else if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) {
// Use DRACO geometry if available
var geometryPromise = extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]
.decodePrimitive(primitive, parser)
.then(function (geometry) {
addPrimitiveAttributes(geometry, primitive, accessors);
return geometry;
});
cache.push({ primitive: primitive, promise: geometryPromise });
pending.push(geometryPromise);
} else {
// Otherwise create a new geometry
var geometry = new THREE.BufferGeometry();
addPrimitiveAttributes(geometry, primitive, accessors);
var geometryPromise = Promise.resolve(geometry);
// Cache this geometry
cache.push({ primitive: primitive, promise: geometryPromise });
pending.push(geometryPromise);
}
}
return Promise.all(pending).then(function (geometries) {
if (isMultiPass) {
var baseGeometry = geometries[0];
// See if we've already created this combined geometry
var cache = parser.multiPassGeometryCache;
var cached = getCachedMultiPassGeometry(cache, baseGeometry, originalPrimitives);
if (cached !== null) return [cached.geometry];
// Cloning geometry because of index override.
// Attributes can be reused so cloning by myself here.
var geometry = new THREE.BufferGeometry();
geometry.name = baseGeometry.name;
geometry.userData = baseGeometry.userData;
for (var key in baseGeometry.attributes) geometry.addAttribute(key, baseGeometry.attributes[key]);
for (var key in baseGeometry.morphAttributes) geometry.morphAttributes[key] = baseGeometry.morphAttributes[key];
var indices = [];
var offset = 0;
for (var i = 0, il = originalPrimitives.length; i < il; i++) {
var accessor = accessors[originalPrimitives[i].indices];
for (var j = 0, jl = accessor.count; j < jl; j++) indices.push(accessor.array[j]);
geometry.addGroup(offset, accessor.count, i);
offset += accessor.count;
}
geometry.setIndex(indices);
cache.push({ geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives });
return [geometry];
} else if (geometries.length > 1 && THREE.BufferGeometryUtils !== undefined) {
// Tries to merge geometries with BufferGeometryUtils if possible
for (var i = 1, il = primitives.length; i < il; i++) {
// can't merge if draw mode is different
if (primitives[0].mode !== primitives[i].mode) return geometries;
}
// See if we've already created this combined geometry
var cache = parser.multiplePrimitivesCache;
var cached = getCachedCombinedGeometry(cache, geometries);
if (cached) {
if (cached.geometry !== null) return [cached.geometry];
} else {
var geometry = THREE.BufferGeometryUtils.mergeBufferGeometries(geometries, true);
cache.push({ geometry: geometry, baseGeometries: geometries });
if (geometry !== null) return [geometry];
}
}
return geometries;
});
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
* @param {number} meshIndex
* @return {Promise<THREE.Group|THREE.Mesh|THREE.SkinnedMesh>}
*/
GLTFParser.prototype.loadMesh = function (meshIndex) {
var scope = this;
var json = this.json;
var extensions = this.extensions;
var meshDef = json.meshes[meshIndex];
return this.getMultiDependencies([
'accessor',
'material'
]).then(function (dependencies) {
var primitives = meshDef.primitives;
var originalMaterials = [];
for (var i = 0, il = primitives.length; i < il; i++) {
originalMaterials[i] = primitives[i].material === undefined
? createDefaultMaterial()
: dependencies.materials[primitives[i].material];
}
return scope.loadGeometries(primitives).then(function (geometries) {
var isMultiMaterial = geometries.length === 1 && geometries[0].groups.length > 0;
var meshes = [];
for (var i = 0, il = geometries.length; i < il; i++) {
var geometry = geometries[i];
var primitive = primitives[i];
// 1. create Mesh
var mesh;
var material = isMultiMaterial ? originalMaterials : originalMaterials[i];
if (primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
primitive.mode === undefined) {
// .isSkinnedMesh isn't in glTF spec. See .markDefs()
mesh = meshDef.isSkinnedMesh === true
? new THREE.SkinnedMesh(geometry, material)
: new THREE.Mesh(geometry, material);
if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP) {
mesh.drawMode = THREE.TriangleStripDrawMode;
} else if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN) {
mesh.drawMode = THREE.TriangleFanDrawMode;
}
} else if (primitive.mode === WEBGL_CONSTANTS.LINES) {
mesh = new THREE.LineSegments(geometry, material);
} else if (primitive.mode === WEBGL_CONSTANTS.LINE_STRIP) {
mesh = new THREE.Line(geometry, material);
} else if (primitive.mode === WEBGL_CONSTANTS.LINE_LOOP) {
mesh = new THREE.LineLoop(geometry, material);
} else if (primitive.mode === WEBGL_CONSTANTS.POINTS) {
mesh = new THREE.Points(geometry, material);
} else {
throw new Error('THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode);
}
if (Object.keys(mesh.geometry.morphAttributes).length > 0) {
updateMorphTargets(mesh, meshDef);
}
mesh.name = meshDef.name || ('mesh_' + meshIndex);
if (geometries.length > 1) mesh.name += '_' + i;
assignExtrasToUserData(mesh, meshDef);
meshes.push(mesh);
// 2. update Material depending on Mesh and BufferGeometry
var materials = isMultiMaterial ? mesh.material : [mesh.material];
var useVertexColors = geometry.attributes.color !== undefined;
var useFlatShading = geometry.attributes.normal === undefined;
var useSkinning = mesh.isSkinnedMesh === true;
var useMorphTargets = Object.keys(geometry.morphAttributes).length > 0;
var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;
for (var j = 0, jl = materials.length; j < jl; j++) {
var material = materials[j];
if (mesh.isPoints) {
var cacheKey = 'PointsMaterial:' + material.uuid;
var pointsMaterial = scope.cache.get(cacheKey);
if (!pointsMaterial) {
pointsMaterial = new THREE.PointsMaterial();
THREE.Material.prototype.copy.call(pointsMaterial, material);
pointsMaterial.color.copy(material.color);
pointsMaterial.map = material.map;
pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
scope.cache.add(cacheKey, pointsMaterial);
}
material = pointsMaterial;
} else if (mesh.isLine) {
var cacheKey = 'LineBasicMaterial:' + material.uuid;
var lineMaterial = scope.cache.get(cacheKey);
if (!lineMaterial) {
lineMaterial = new THREE.LineBasicMaterial();
THREE.Material.prototype.copy.call(lineMaterial, material);
lineMaterial.color.copy(material.color);
lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
scope.cache.add(cacheKey, lineMaterial);
}
material = lineMaterial;
}
// Clone the material if it will be modified
if (useVertexColors || useFlatShading || useSkinning || useMorphTargets) {
var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:';
if (useSkinning) cacheKey += 'skinning:';
if (useVertexColors) cacheKey += 'vertex-colors:';
if (useFlatShading) cacheKey += 'flat-shading:';
if (useMorphTargets) cacheKey += 'morph-targets:';
if (useMorphNormals) cacheKey += 'morph-normals:';
var cachedMaterial = scope.cache.get(cacheKey);
if (!cachedMaterial) {
cachedMaterial = material.isGLTFSpecularGlossinessMaterial
? extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].cloneMaterial(material)
: material.clone();
if (useSkinning) cachedMaterial.skinning = true;
if (useVertexColors) cachedMaterial.vertexColors = THREE.VertexColors;
if (useFlatShading) cachedMaterial.flatShading = true;
if (useMorphTargets) cachedMaterial.morphTargets = true;
if (useMorphNormals) cachedMaterial.morphNormals = true;
scope.cache.add(cacheKey, cachedMaterial);
}
material = cachedMaterial;
}
materials[j] = material;
// workarounds for mesh and geometry
if (material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined) {
console.log('THREE.GLTFLoader: Duplicating UVs to support aoMap.');
geometry.addAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2));
}
if (material.isGLTFSpecularGlossinessMaterial) {
// for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update
mesh.onBeforeRender = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].refreshUniforms;
}
}
mesh.material = isMultiMaterial ? materials : materials[0];
}
if (meshes.length === 1) {
return meshes[0];
}
var group = new THREE.Group();
for (var i = 0, il = meshes.length; i < il; i++) {
group.add(meshes[i]);
}
return group;
});
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
* @param {number} cameraIndex
* @return {Promise<THREE.Camera>}
*/
GLTFParser.prototype.loadCamera = function (cameraIndex) {
var camera;
var cameraDef = this.json.cameras[cameraIndex];
var params = cameraDef[cameraDef.type];
if (!params) {
console.warn('THREE.GLTFLoader: Missing camera parameters.');
return;
}
if (cameraDef.type === 'perspective') {
camera = new THREE.PerspectiveCamera(THREE.Math.radToDeg(params.yfov), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6);
} else if (cameraDef.type === 'orthographic') {
camera = new THREE.OrthographicCamera(params.xmag / - 2, params.xmag / 2, params.ymag / 2, params.ymag / - 2, params.znear, params.zfar);
}
if (cameraDef.name !== undefined) camera.name = cameraDef.name;
assignExtrasToUserData(camera, cameraDef);
return Promise.resolve(camera);
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
* @param {number} skinIndex
* @return {Promise<Object>}
*/
GLTFParser.prototype.loadSkin = function (skinIndex) {
var skinDef = this.json.skins[skinIndex];
var skinEntry = { joints: skinDef.joints };
if (skinDef.inverseBindMatrices === undefined) {
return Promise.resolve(skinEntry);
}
return this.getDependency('accessor', skinDef.inverseBindMatrices).then(function (accessor) {
skinEntry.inverseBindMatrices = accessor;
return skinEntry;
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
* @param {number} animationIndex
* @return {Promise<THREE.AnimationClip>}
*/
GLTFParser.prototype.loadAnimation = function (animationIndex) {
var json = this.json;
var animationDef = json.animations[animationIndex];
return this.getMultiDependencies([
'accessor',
'node'
]).then(function (dependencies) {
var tracks = [];
for (var i = 0, il = animationDef.channels.length; i < il; i++) {
var channel = animationDef.channels[i];
var sampler = animationDef.samplers[channel.sampler];
if (sampler) {
var target = channel.target;
var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
var input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input;
var output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output;
var inputAccessor = dependencies.accessors[input];
var outputAccessor = dependencies.accessors[output];
var node = dependencies.nodes[name];
if (node) {
node.updateMatrix();
node.matrixAutoUpdate = true;
var TypedKeyframeTrack;
switch (PATH_PROPERTIES[target.path]) {
case PATH_PROPERTIES.weights:
TypedKeyframeTrack = THREE.NumberKeyframeTrack;
break;
case PATH_PROPERTIES.rotation:
TypedKeyframeTrack = THREE.QuaternionKeyframeTrack;
break;
case PATH_PROPERTIES.position:
case PATH_PROPERTIES.scale:
default:
TypedKeyframeTrack = THREE.VectorKeyframeTrack;
break;
}
var targetName = node.name ? node.name : node.uuid;
var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[sampler.interpolation] : THREE.InterpolateLinear;
var targetNames = [];
if (PATH_PROPERTIES[target.path] === PATH_PROPERTIES.weights) {
// node can be THREE.Group here but
// PATH_PROPERTIES.weights(morphTargetInfluences) should be
// the property of a mesh object under group.
node.traverse(function (object) {
if (object.isMesh === true && object.morphTargetInfluences) {
targetNames.push(object.name ? object.name : object.uuid);
}
});
} else {
targetNames.push(targetName);
}
// KeyframeTrack.optimize() will modify given 'times' and 'values'
// buffers before creating a truncated copy to keep. Because buffers may
// be reused by other tracks, make copies here.
for (var j = 0, jl = targetNames.length; j < jl; j++) {
var track = new TypedKeyframeTrack(
targetNames[j] + '.' + PATH_PROPERTIES[target.path],
THREE.AnimationUtils.arraySlice(inputAccessor.array, 0),
THREE.AnimationUtils.arraySlice(outputAccessor.array, 0),
interpolation
);
// Here is the trick to enable custom interpolation.
// Overrides .createInterpolant in a factory method which creates custom interpolation.
if (sampler.interpolation === 'CUBICSPLINE') {
track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) {
// A CUBICSPLINE keyframe in glTF has three output values for each input value,
// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
// must be divided by three to get the interpolant's sampleSize argument.
return new GLTFCubicSplineInterpolant(this.times, this.values, this.getValueSize() / 3, result);
};
// Workaround, provide an alternate way to know if the interpolant type is cubis spline to track.
// track.getInterpolation() doesn't return valid value for custom interpolant.
track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
}
tracks.push(track);
}
}
}
}
var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex;
return new THREE.AnimationClip(name, undefined, tracks);
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
* @param {number} nodeIndex
* @return {Promise<THREE.Object3D>}
*/
GLTFParser.prototype.loadNode = function (nodeIndex) {
var json = this.json;
var extensions = this.extensions;
var meshReferences = json.meshReferences;
var meshUses = json.meshUses;
var nodeDef = json.nodes[nodeIndex];
return this.getMultiDependencies([
'mesh',
'skin',
'camera',
'light'
]).then(function (dependencies) {
var node;
// .isBone isn't in glTF spec. See .markDefs
if (nodeDef.isBone === true) {
node = new THREE.Bone();
} else if (nodeDef.mesh !== undefined) {
var mesh = dependencies.meshes[nodeDef.mesh];
if (meshReferences[nodeDef.mesh] > 1) {
var instanceNum = meshUses[nodeDef.mesh]++;
node = mesh.clone();
node.name += '_instance_' + instanceNum;
// onBeforeRender copy for Specular-Glossiness
node.onBeforeRender = mesh.onBeforeRender;
for (var i = 0, il = node.children.length; i < il; i++) {
node.children[i].name += '_instance_' + instanceNum;
node.children[i].onBeforeRender = mesh.children[i].onBeforeRender;
}
} else {
node = mesh;
}
} else if (nodeDef.camera !== undefined) {
node = dependencies.cameras[nodeDef.camera];
} else if (nodeDef.extensions
&& nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL]
&& nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light !== undefined) {
var lights = extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].lights;
node = lights[nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light];
} else {
node = new THREE.Object3D();
}
if (nodeDef.name !== undefined) {
node.name = THREE.PropertyBinding.sanitizeNodeName(nodeDef.name);
}
assignExtrasToUserData(node, nodeDef);
if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef);
if (nodeDef.matrix !== undefined) {
var matrix = new THREE.Matrix4();
matrix.fromArray(nodeDef.matrix);
node.applyMatrix(matrix);
} else {
if (nodeDef.translation !== undefined) {
node.position.fromArray(nodeDef.translation);
}
if (nodeDef.rotation !== undefined) {
node.quaternion.fromArray(nodeDef.rotation);
}
if (nodeDef.scale !== undefined) {
node.scale.fromArray(nodeDef.scale);
}
}
return node;
});
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
* @param {number} sceneIndex
* @return {Promise<THREE.Scene>}
*/
GLTFParser.prototype.loadScene = function () {
// scene node hierachy builder
function buildNodeHierachy(nodeId, parentObject, json, allNodes, skins) {
var node = allNodes[nodeId];
var nodeDef = json.nodes[nodeId];
// build skeleton here as well
if (nodeDef.skin !== undefined) {
var meshes = node.isGroup === true ? node.children : [node];
for (var i = 0, il = meshes.length; i < il; i++) {
var mesh = meshes[i];
var skinEntry = skins[nodeDef.skin];
var bones = [];
var boneInverses = [];
for (var j = 0, jl = skinEntry.joints.length; j < jl; j++) {
var jointId = skinEntry.joints[j];
var jointNode = allNodes[jointId];
if (jointNode) {
bones.push(jointNode);
var mat = new THREE.Matrix4();
if (skinEntry.inverseBindMatrices !== undefined) {
mat.fromArray(skinEntry.inverseBindMatrices.array, j * 16);
}
boneInverses.push(mat);
} else {
console.warn('THREE.GLTFLoader: Joint "%s" could not be found.', jointId);
}
}
mesh.bind(new THREE.Skeleton(bones, boneInverses), mesh.matrixWorld);
}
}
// build node hierachy
parentObject.add(node);
if (nodeDef.children) {
var children = nodeDef.children;
for (var i = 0, il = children.length; i < il; i++) {
var child = children[i];
buildNodeHierachy(child, node, json, allNodes, skins);
}
}
}
return function loadScene(sceneIndex) {
var json = this.json;
var extensions = this.extensions;
var sceneDef = this.json.scenes[sceneIndex];
return this.getMultiDependencies([
'node',
'skin'
]).then(function (dependencies) {
var scene = new THREE.Scene();
if (sceneDef.name !== undefined) scene.name = sceneDef.name;
assignExtrasToUserData(scene, sceneDef);
if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef);
var nodeIds = sceneDef.nodes || [];
for (var i = 0, il = nodeIds.length; i < il; i++) {
buildNodeHierachy(nodeIds[i], scene, json, dependencies.nodes, dependencies.skins);
}
return scene;
});
};
}();
return GLTFLoader;
})();
function decodeText(array) {
if (typeof TextDecoder !== 'undefined') {
return new TextDecoder().decode(array);
}
// Avoid the String.fromCharCode.apply(null, array) shortcut, which
// throws a "maximum call stack size exceeded" error for large arrays.
var s = '';
for (var i = 0, il = array.length; i < il; i++) {
// Implicitly assumes little-endian.
s += String.fromCharCode(array[i]);
}
// Merges multi-byte utf-8 characters.
return decodeURIComponent(escape(s));
}
function GLTFBinaryExtension(data) {
this.name = EXTENSIONS.KHR_BINARY_GLTF;
this.content = null;
this.body = null;
var headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
this.header = {
magic: decodeText(new Uint8Array(data.slice(0, 4))),
version: headerView.getUint32(4, true),
length: headerView.getUint32(8, true)
};
if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {
throw new Error('THREE.GLTFLoader: Unsupported glTF-Binary header.');
} else if (this.header.version < 2.0) {
throw new Error('THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.');
}
var chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);
var chunkIndex = 0;
while (chunkIndex < chunkView.byteLength) {
var chunkLength = chunkView.getUint32(chunkIndex, true);
chunkIndex += 4;
var chunkType = chunkView.getUint32(chunkIndex, true);
chunkIndex += 4;
if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
var contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
this.content = decodeText(contentArray);
} else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
this.body = data.slice(byteOffset, byteOffset + chunkLength);
}
// Clients must ignore chunks with unknown types.
chunkIndex += chunkLength;
}
if (this.content === null) {
throw new Error('THREE.GLTFLoader: JSON content not found.');
}
}
/* UTILITY FUNCTIONS */
function resolveURL(url, path) {
// Invalid URL
if (typeof url !== 'string' || url === '') return '';
// Absolute URL http://,https://,//
if (/^(https?:)?\/\//i.test(url)) return url;
// Data URI
if (/^data:.*,.*$/i.test(url)) return url;
// Blob URL
if (/^blob:.*$/i.test(url)) return url;
// Relative URL
return path + url;
}
\ No newline at end of file
......@@ -27,6 +27,10 @@ export class Geometry extends HashObject {
boundingBox: Box3 = null;
boundingSphere: Sphere = null;
/**
* 是否按面检测
*/
doHitFace: boolean = false;
/**
* 为了不同渲染器上下文对应自己的vao,不管program吧,可能不同着色器程序,带的attr可能不一样,
* 在3d的插件上处理
......@@ -74,15 +78,14 @@ export class Geometry extends HashObject {
//顶点长度先记录
this._attrBuffer = new BatchBuffer(vertices.length / 3 * this._vertByteSize);
// this.computeBoundingBox();
}
computeBoundingBox() {
if (this.boundingBox === null) this.boundingBox = new Box3();
if (!this.boundingBox) this.boundingBox = new Box3();
var position = this._vertices;
if (position !== undefined) {
if (position) {
this.boundingBox.setFromArray(position);
} else {
this.boundingBox.makeEmpty();
......@@ -96,7 +99,7 @@ export class Geometry extends HashObject {
var box = new Box3();
var vector = new Vector3();
if (this.boundingSphere === null) this.boundingSphere = new Sphere();
if (!this.boundingSphere) this.boundingSphere = new Sphere();
var position = this._vertices;
......
......@@ -47,6 +47,16 @@ export class Mesh3D extends Object3D {
// Check boundingBox before continuing
if (geometry.boundingBox !== null && tempRay.intersectsBox(geometry.boundingBox) === false) return;
//如果不需要面检测,到此为止了
if (!geometry.doHitFace) {
// raycaster.ray.origin.distanceTo(templeSphere.center) - templeSphere.radius,
intersects.push({//距离简单点
distance: raycaster.ray.origin.distanceTo(templeSphere.center) - templeSphere.radius,
object: this
})
return;
}
var intersection: IntersectData;
var a = new Vector3(), b = new Vector3(), c = new Vector3();
......@@ -55,10 +65,10 @@ export class Mesh3D extends Object3D {
if (index) {
for (var i = 0; i < index.length; i += 3) {
a.set(position[i * 3], position[i * 3 + 1], position[i * 3 + 2]);
b.set(position[(i + 1) * 3], position[(i + 1) * 3 + 1], position[(i + 1) * 3 + 2]);
c.set(position[(i + 2) * 3], position[(i + 2) * 3 + 1], position[(i + 2) * 3 + 2]);
var i1 = index[i], i2 = index[i + 1], i3 = index[i + 2];
a.set(position[i1 * 3], position[i1 * 3 + 1], position[i1 * 3 + 2]);
b.set(position[i2 * 3], position[i2 * 3 + 1], position[i2 * 3 + 2]);
c.set(position[i3 * 3], position[i3 * 3 + 1], position[i3 * 3 + 2]);
intersection = checkIntersection(
this,
raycaster,
......@@ -76,10 +86,9 @@ export class Mesh3D extends Object3D {
}
else if (position) {
for (var i = 0; i < position.length; i += 9) {
a.set(position[i * 3], position[i * 3 + 1], position[i * 3 + 2]);
b.set(position[(i + 1) * 3], position[(i + 1) * 3 + 1], position[(i + 1) * 3 + 2]);
c.set(position[(i + 2) * 3], position[(i + 2) * 3 + 1], position[(i + 2) * 3 + 2]);
a.set(position[i], position[i + 1], position[i + 2]);
b.set(position[i + 3], position[i + 4], position[i + 5]);
c.set(position[i + 6], position[i + 7], position[i + 8]);
intersection = checkIntersection(
this,
raycaster,
......
......@@ -209,8 +209,11 @@ export class Object3D extends EventDispatcher {
};
globalToLocal(vector: Vector3) {
var m1 = new Matrix4();
return vector.applyMatrix4(m1.setInverseOf(this._worldMatrix));
if (vector instanceof Vector3) {
var m1 = new Matrix4();
return vector.applyMatrix4(m1.setInverseOf(this._worldMatrix));
}
return vector
};
updateLocalMatrix() {
......
......@@ -10,8 +10,8 @@ import { Mesh3D } from './Mesh3D';
export class Raycaster {
public ray: Ray
constructor(
origin: Vector3,
direction: Vector3,
origin?: Vector3,
direction?: Vector3,
public near: number = 0,
public far: number = Infinity
) {
......@@ -73,7 +73,7 @@ function intersectObject(object: Object3D, raycaster: Raycaster, intersects: Int
export interface IntersectData {
distance: number,
point: Vector3,
point?: Vector3,
object: Object3D,
uv?: Vector2,//以后再说
// face?:Face3,
......
......@@ -7,7 +7,7 @@ import { Light } from "./lights/Light";
import { PointLight } from "./lights/PointLight";
import { DirectionalLight } from "./lights/DirectionalLight";
import { Vector3 } from "./math/Vector3";
import { Point } from "../2d/math";
import { Point, Matrix } from "../2d/math";
import { Vector2 } from "./math/Vector2";
import { MouseEvent } from "../2d/events";
import { Raycaster } from "./Raycaster";
......@@ -72,15 +72,13 @@ export class Scene3D extends Object3D {
*/
camera: Camera;
private raycaster:Raycaster
private raycaster: Raycaster = new Raycaster()
constructor() {
super()
this._instanceType = "Scene3D";
//@ts-ignore为了添加进容器时候的操作,做个兼容
this.transform = { _parentId: 0 }
this.camera = new PerspectiveCamera();
// this.raycaster = new Raycaster();
}
//只处理自己的xy坐标
updateTransform() {
......@@ -185,20 +183,17 @@ export class Scene3D extends Object3D {
}
//检查场景中的
if (this.mouseChildren) {
//canvas上的坐标,转成视窗内的坐标,暂时不管旋转的,也不允许scene3D视窗旋转
x = ((globalPoint.x - x) / w) * 2 - 1;
y = - ((globalPoint.y - y) / h) * 2 + 1;
this.raycaster.setFromCamera(new Vector3(x, y, 0.5), this.camera);
//只需要距离最近的那个就行
var arr = this.raycaster.intersectObject(this)
if (arr.length) return arr[0].object
}
return this;
}
/**
* 为了兼容stage里鼠标事件需要计算localX和localY
* @param vector
*/
globalToLocal(vector: Vector3) {
return vector
}
//相机控件
setOrbitControl() {
// sphericalDelta.theta *= ( 1 - scope.dampingFactor );
......@@ -302,7 +297,7 @@ export class Scene3D extends Object3D {
//事件,暂时只有旋转,其他判断先不要了
this.addEventListener(MouseEvent.MOUSE_DOWN, (e: MouseEvent) => {
e.stopPropagation();
// e.stopPropagation();
rotateStart.set(e.clientX, e.clientY);
this.addEventListener(MouseEvent.MOUSE_MOVE, move, this);
......@@ -350,4 +345,25 @@ interface PointLightConfig {
interface DirectionalLightConfig {
direction: number[],
color: number[],
}
\ No newline at end of file
}
// window['$'].ajax({
// type: "get",
// url: "//embedlog.duiba.com.cn/exposure/standard",
// dataType: "jsonp",
// data: {
// dpm: 72915 + '.' + 110 + '.' + 1 + '.' + 1,
// dcm: 202 + '.' + 1 + '.' + 0 + '.' + 0,
// appId: 72915,
// domain: '//embedlog.duiba.com.cn'
// },
// async: true,
// success: (result) => {
// },
// error: (message) => {
// }
// });
\ No newline at end of file
import { Geometry } from "../Geometry";
import { Vector3 } from "../math/Vector3";
import { Box3 } from "../math/Box3";
import { Sphere } from "../math/Sphere";
/**
* 顶点创建方式直接用three的
* 以后记录长宽高属性,标记是否更新顶点等数据
*/
export class BoxGeometry extends Geometry {
/**
*
* @param width x
* @param height y
* @param depth z
* @param widthSegments
* @param heightSegments
* @param depthSegments
*/
constructor(
width: number = 1,
height: number = 1,
......@@ -146,5 +158,16 @@ export class BoxGeometry extends Geometry {
}
//传入数据
super(vertices, indices, normals, null, uvs)
//直接计算包围盒
this.boundingBox = new Box3(
new Vector3(-width / 2, -height / 2, -depth / 2),
new Vector3(width / 2, height / 2, depth / 2)
)
//直接计算包围球
this.boundingSphere = new Sphere(
new Vector3(),
Math.sqrt(width * width + height * height + depth * depth)
)
}
}
\ No newline at end of file
import { Geometry } from "../Geometry";
import { Vector3 } from "..";
import { Sphere } from "../math/Sphere";
/**
* 球形几何
......@@ -81,6 +82,12 @@ export class SphereGeometry extends Geometry {
if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d);
}
}
super(vertices, indices, normals, null, uvs)
super(vertices, indices, normals, null, uvs);
//直接计算包围球
this.boundingSphere = new Sphere(
new Vector3(),
radius
)
}
}
\ No newline at end of file
......@@ -130,7 +130,7 @@
//加入舞台
stage.addChild(scene);
//相机在场景里面
scene.camera.position.set(10, 10, 14)
scene.camera.position.set(6, 6, 14)
scene.camera.lookAt(0, 0, 0)
//设置一下相机的比例
scene.camera.set(undefined, stage.viewRect.width / stage.viewRect.height)
......@@ -161,6 +161,7 @@
.to({ y: 450 }, 500000 * 3)
// m.visible = false;
m.position.y = 0
m.addEventListener(FYGE.MouseEvent.CLICK,()=>{console.log(123123)},this)
//不带光找的材质
var mat1 = new FYGE.BaseMaterial();
......@@ -209,11 +210,12 @@
mat2.side = 1//从里往外看,可见材质面取顺时针,
mat2.map = textureSky;
var m = scene.addChildAt(new FYGE.Mesh3D(geos, mat2), 0)
m.mouseEnable=false
// m.position.set(0, 2, 0)
// m.scale.set(1, 1, 1)
//坐标轴
scene.addChild(new FYGE.AxesHelper(10000))
// scene.addChild(new FYGE.AxesHelper(10000))
//平面
var geop = new FYGE.PlaneGeometry(20, 30)
......@@ -238,6 +240,10 @@
var a = scene.addChild(new FYGE.Mesh3D(geo, mat1));
a.position.copy(l.position)
a.scale.set(0.1, 0.1, 0.1)
a.addEventListener(FYGE.MouseEvent.MOUSE_DOWN,()=>{
console.log(654564)
},this)
}
}, this);
......
......@@ -4,7 +4,7 @@ var path = require('path');
var webpack = require('webpack')
module.exports = {
mode: "production",//'development',production
mode: "development",//'development',production
entry: {
"fyge.min": "./src/index.ts",
},
......@@ -25,9 +25,9 @@ module.exports = {
},
devtool: 'source-map',
plugins: [
new UglifyJSPlugin(
{ sourceMap: true }
),
// new UglifyJSPlugin(
// { sourceMap: true }
// ),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment