|
|
@@ -1,5 +1,5 @@
|
|
|
-import * as THREE from "three";
|
|
|
-import { THREEMaterialType, IBaseProps, IGroupParams, IMeshParams, IPointLight } from "./type/types";
|
|
|
+import * as THREE from 'three';
|
|
|
+import { THREEMaterialType, IBaseProps, IGroupParams, IMeshParams, IPointLight } from './type/types';
|
|
|
|
|
|
/**
|
|
|
* glb模型并发加载工作原理
|
|
|
@@ -15,226 +15,222 @@ import { THREEMaterialType, IBaseProps, IGroupParams, IMeshParams, IPointLight }
|
|
|
/**
|
|
|
* 通过设置attributes index来复刻一个集合体
|
|
|
*/
|
|
|
-const genGeometry = (geometry: IMeshParams["geometry"], IMeshParams) => {
|
|
|
- // console.log('目标------>',geometry);
|
|
|
- const geom = new THREE.BufferGeometry();
|
|
|
- const {
|
|
|
- attributes: { position, uv, normal },
|
|
|
- index,
|
|
|
- } = geometry;
|
|
|
-
|
|
|
-
|
|
|
- //处理几何坐标
|
|
|
- if(uv){
|
|
|
- const attributes = {
|
|
|
- position: new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
|
|
|
- uv: new THREE.BufferAttribute(uv.array, uv.itemSize, uv.normalized),
|
|
|
- normal: new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized),
|
|
|
- };
|
|
|
- geom.attributes = attributes;
|
|
|
- }else {
|
|
|
- const attributes = {
|
|
|
- position: new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
|
|
|
- normal: new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized),
|
|
|
- };
|
|
|
- // geom.attributes['position'] = new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
|
|
|
- // geom.attributes['normal'] = new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized)
|
|
|
- geom.attributes = attributes;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- geom.index = index ? new THREE.BufferAttribute(index.array, index.itemSize, index.normalized) : null;
|
|
|
- return geom;
|
|
|
+const genGeometry = (geometry: IMeshParams['geometry'], IMeshParams) => {
|
|
|
+ // console.log('目标------>',geometry);
|
|
|
+ const geom = new THREE.BufferGeometry();
|
|
|
+ const {
|
|
|
+ attributes: { position, uv, normal },
|
|
|
+ index,
|
|
|
+ } = geometry;
|
|
|
+
|
|
|
+ //处理几何坐标
|
|
|
+ if (uv) {
|
|
|
+ const attributes = {
|
|
|
+ position: new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
|
|
|
+ uv: new THREE.BufferAttribute(uv.array, uv.itemSize, uv.normalized),
|
|
|
+ normal: new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized),
|
|
|
+ };
|
|
|
+ geom.attributes = attributes;
|
|
|
+ } else {
|
|
|
+ const attributes = {
|
|
|
+ position: new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
|
|
|
+ normal: new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized),
|
|
|
+ };
|
|
|
+ // geom.attributes['position'] = new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
|
|
|
+ // geom.attributes['normal'] = new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized)
|
|
|
+ geom.attributes = attributes;
|
|
|
+ }
|
|
|
+
|
|
|
+ geom.index = index ? new THREE.BufferAttribute(index.array, index.itemSize, index.normalized) : null;
|
|
|
+ return geom;
|
|
|
};
|
|
|
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* 根据传入纹理的参数生成真正有效的Material类型数据
|
|
|
*/
|
|
|
-const genMaterial = (mate: IMeshParams["material"]) => {
|
|
|
- if (!mate) return undefined;
|
|
|
- const multipleMaterial = Array.isArray(mate);
|
|
|
- const material = multipleMaterial ? ([] as THREE.Material[]) : new THREE[mate.type as THREEMaterialType]();
|
|
|
- //处理材质
|
|
|
- //多个材质
|
|
|
- if (multipleMaterial && Array.isArray(material)) {
|
|
|
- console.log('有多个材质');
|
|
|
-
|
|
|
- for (const m of mate) {
|
|
|
- const im = new THREE[m.type as THREEMaterialType]();
|
|
|
-
|
|
|
- material.push(im);
|
|
|
+const genMaterial = (mate: IMeshParams['material']) => {
|
|
|
+ if (!mate) return undefined;
|
|
|
+ const multipleMaterial = Array.isArray(mate);
|
|
|
+ const material = multipleMaterial ? ([] as THREE.Material[]) : new THREE[mate.type as THREEMaterialType]();
|
|
|
+ //处理材质
|
|
|
+ //多个材质
|
|
|
+ if (multipleMaterial && Array.isArray(material)) {
|
|
|
+ console.log('有多个材质');
|
|
|
+
|
|
|
+ for (const m of mate) {
|
|
|
+ const im = new THREE[m.type as THREEMaterialType]();
|
|
|
+
|
|
|
+ material.push(im);
|
|
|
+ }
|
|
|
+ } else if (mate) {
|
|
|
+ //单个材质
|
|
|
+ Object.assign(material, mate);
|
|
|
+ for (const key in mate) {
|
|
|
+ if (Object.prototype.hasOwnProperty.call(mate, key)) {
|
|
|
+ const element = mate[key];
|
|
|
+ if (element && Object.prototype.toString.call(element === '[object Object]')) {
|
|
|
+ if (element.isTexture) {
|
|
|
+ const texture = new THREE.Texture();
|
|
|
+ for (const k in texture) {
|
|
|
+ if (Object.prototype.toString.call(texture[k]) === '[object Object]') {
|
|
|
+ if (k === 'center' || k === 'offset' || k === 'repeat') {
|
|
|
+ texture[k] = new THREE.Vector2();
|
|
|
+ }
|
|
|
+ if (k === 'matrix') {
|
|
|
+ texture[k] = new THREE.Matrix3();
|
|
|
+ }
|
|
|
+ if (k === 'source') {
|
|
|
+ texture[k] = new THREE.Source(null);
|
|
|
+ }
|
|
|
+ Object.assign(texture[k], element[k]);
|
|
|
+ } else {
|
|
|
+ texture[k] = element[k];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ material[key] = texture;
|
|
|
+ }
|
|
|
+ if (element.isColor) {
|
|
|
+ const color = new THREE.Color();
|
|
|
+ Object.assign(color, element);
|
|
|
+ material[key] = color;
|
|
|
+ }
|
|
|
+ if (key === 'normalScale') {
|
|
|
+ const vector2 = new THREE.Vector2();
|
|
|
+ Object.assign(vector2, element);
|
|
|
+ material[key] = vector2;
|
|
|
+ }
|
|
|
}
|
|
|
- } else if (mate) {
|
|
|
- //单个材质
|
|
|
- Object.assign(material, mate);
|
|
|
- for (const key in mate) {
|
|
|
- if (Object.prototype.hasOwnProperty.call(mate, key)) {
|
|
|
- const element = mate[key];
|
|
|
- if(element && Object.prototype.toString.call(element === '[object Object]')) {
|
|
|
- if( element.isTexture){
|
|
|
- const texture = new THREE.Texture()
|
|
|
- for (const k in texture) {
|
|
|
- if(Object.prototype.toString.call(texture[k]) === '[object Object]'){
|
|
|
- if(k==='center' || k==='offset' || k==='repeat'){
|
|
|
- texture[k] = new THREE.Vector2()
|
|
|
- }
|
|
|
- if(k === 'matrix'){
|
|
|
- texture[k] = new THREE.Matrix3()
|
|
|
- }
|
|
|
- if(k === 'source'){
|
|
|
- texture[k] = new THREE.Source(null)
|
|
|
- }
|
|
|
- Object.assign(texture[k] , element[k]);
|
|
|
- }else {
|
|
|
- texture[k] = element[k]
|
|
|
- }
|
|
|
- }
|
|
|
- material[key] = texture
|
|
|
- }
|
|
|
- if(element.isColor){
|
|
|
- const color = new THREE.Color()
|
|
|
- Object.assign(color, element);
|
|
|
- material[key] = color
|
|
|
- }
|
|
|
- if(key === 'normalScale'){
|
|
|
- const vector2 = new THREE.Vector2()
|
|
|
- Object.assign(vector2, element);
|
|
|
- material[key] = vector2
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return material;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return material;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 处理基本属性转换(Object3D基类上的属性) matrix scale rotate translate position children animations
|
|
|
*/
|
|
|
const parseBaseParams = (params: IBaseProps, object: THREE.Object3D) => {
|
|
|
- const matrix = new THREE.Matrix4();
|
|
|
- matrix.elements = params.matrix.elements;
|
|
|
- object.name = params.name;
|
|
|
- object.matrix = matrix;
|
|
|
- object.rotation.set(...params.rotation);
|
|
|
- object.position.set(...params.position);
|
|
|
- object.scale.set(...params.scale);
|
|
|
- object.quaternion.set(...params.quaternion);
|
|
|
- object.up.set(...params.up);
|
|
|
- object.userData = params.userData;
|
|
|
- object.visible = params.visible;
|
|
|
-
|
|
|
- parseChildren(object, params.children);
|
|
|
- genAnimations(object, params.animations);
|
|
|
- // deleteObjectKeys(params, [
|
|
|
- // "name",
|
|
|
- // "matrix",
|
|
|
- // "rotation",
|
|
|
- // "position",
|
|
|
- // "scale",
|
|
|
- // "quaternion",
|
|
|
- // "up",
|
|
|
- // "userData",
|
|
|
- // "visible",
|
|
|
- // ]);
|
|
|
- // object.scale.x += 0.3;
|
|
|
- // object.scale.y += 0.3;
|
|
|
- // object.scale.z += 0.3;
|
|
|
+ const matrix = new THREE.Matrix4();
|
|
|
+ matrix.elements = params.matrix.elements;
|
|
|
+ object.name = params.name;
|
|
|
+ object.matrix = matrix;
|
|
|
+ object.rotation.set(...params.rotation);
|
|
|
+ object.position.set(...params.position);
|
|
|
+ object.scale.set(...params.scale);
|
|
|
+ object.quaternion.set(...params.quaternion);
|
|
|
+ object.up.set(...params.up);
|
|
|
+ object.userData = params.userData;
|
|
|
+ object.visible = params.visible;
|
|
|
+
|
|
|
+ parseChildren(object, params.children);
|
|
|
+ genAnimations(object, params.animations);
|
|
|
+ // deleteObjectKeys(params, [
|
|
|
+ // "name",
|
|
|
+ // "matrix",
|
|
|
+ // "rotation",
|
|
|
+ // "position",
|
|
|
+ // "scale",
|
|
|
+ // "quaternion",
|
|
|
+ // "up",
|
|
|
+ // "userData",
|
|
|
+ // "visible",
|
|
|
+ // ]);
|
|
|
+ // object.scale.x += 0.3;
|
|
|
+ // object.scale.y += 0.3;
|
|
|
+ // object.scale.z += 0.3;
|
|
|
};
|
|
|
|
|
|
const parseMesh = (IMeshParams: IMeshParams) => {
|
|
|
- const geometry = genGeometry(IMeshParams.geometry, IMeshParams);
|
|
|
- const material = genMaterial(IMeshParams.material);
|
|
|
+ const geometry = genGeometry(IMeshParams.geometry, IMeshParams);
|
|
|
+ const material = genMaterial(IMeshParams.material);
|
|
|
|
|
|
- const mesh = new THREE.Mesh(geometry, material);
|
|
|
- parseBaseParams(IMeshParams, mesh);
|
|
|
- return mesh;
|
|
|
+ const mesh = new THREE.Mesh(geometry, material);
|
|
|
+ parseBaseParams(IMeshParams, mesh);
|
|
|
+ return mesh;
|
|
|
};
|
|
|
|
|
|
const parseGroup = (params: IGroupParams) => {
|
|
|
- const group = new THREE.Group();
|
|
|
- parseBaseParams(params, group);
|
|
|
- return group;
|
|
|
+ const group = new THREE.Group();
|
|
|
+ parseBaseParams(params, group);
|
|
|
+ return group;
|
|
|
};
|
|
|
|
|
|
const parsePointLight = (params: IPointLight) => {
|
|
|
- const color = new THREE.Color();
|
|
|
- // 色彩空间
|
|
|
- // export type ColorSpace = NoColorSpace | SRGBColorSpace | LinearSRGBColorSpace;
|
|
|
- // export type NoColorSpace = '';
|
|
|
- // export type SRGBColorSpace = 'srgb';
|
|
|
- // export type LinearSRGBColorSpace = 'srgb-linear';
|
|
|
- //glb模型为了亮度恢复 使用srgb格式 所以颜色也使用同样格式 使其颜色模式一致
|
|
|
- color.setRGB(params.color.r, params.color.g, params.color.b, "srgb-linear");
|
|
|
-
|
|
|
- const pointLight = new THREE.PointLight(color, params.intensity, params.distance, params.decay);
|
|
|
- parseBaseParams(params, pointLight);
|
|
|
- return pointLight;
|
|
|
+ const color = new THREE.Color();
|
|
|
+ // 色彩空间
|
|
|
+ // export type ColorSpace = NoColorSpace | SRGBColorSpace | LinearSRGBColorSpace;
|
|
|
+ // export type NoColorSpace = '';
|
|
|
+ // export type SRGBColorSpace = 'srgb';
|
|
|
+ // export type LinearSRGBColorSpace = 'srgb-linear';
|
|
|
+ //glb模型为了亮度恢复 使用srgb格式 所以颜色也使用同样格式 使其颜色模式一致
|
|
|
+ color.setRGB(params.color.r, params.color.g, params.color.b, 'srgb-linear');
|
|
|
+
|
|
|
+ const pointLight = new THREE.PointLight(color, params.intensity, params.distance, params.decay);
|
|
|
+ parseBaseParams(params, pointLight);
|
|
|
+ return pointLight;
|
|
|
};
|
|
|
|
|
|
const parseObject3D = (params: IBaseProps) => {
|
|
|
- const object = new THREE.Object3D();
|
|
|
- parseBaseParams(params, object);
|
|
|
- return object;
|
|
|
+ const object = new THREE.Object3D();
|
|
|
+ parseBaseParams(params, object);
|
|
|
+ return object;
|
|
|
};
|
|
|
|
|
|
const parseChildren = (object3D: THREE.Object3D, children: IBaseProps[]) => {
|
|
|
- if (!children.length) return;
|
|
|
- const objectList: THREE.Object3D[] = [];
|
|
|
- for (const child of children) {
|
|
|
- const { type } = child;
|
|
|
- if (type === "Mesh") {
|
|
|
- objectList.push(parseMesh(child as IMeshParams));
|
|
|
- } else if (type === "Group") {
|
|
|
- objectList.push(parseGroup(child));
|
|
|
- } else if (type === "PointLight") {
|
|
|
- objectList.push(parsePointLight(child as IPointLight));
|
|
|
- } else if (type === "Object3D") {
|
|
|
- objectList.push(parseObject3D(child));
|
|
|
- } else {
|
|
|
- throw new Error("出现了未处理的类型:" + type);
|
|
|
- }
|
|
|
+ if (!children.length) return;
|
|
|
+ const objectList: THREE.Object3D[] = [];
|
|
|
+ for (const child of children) {
|
|
|
+ const { type } = child;
|
|
|
+ if (type === 'Mesh') {
|
|
|
+ objectList.push(parseMesh(child as IMeshParams));
|
|
|
+ } else if (type === 'Group') {
|
|
|
+ objectList.push(parseGroup(child));
|
|
|
+ } else if (type === 'PointLight') {
|
|
|
+ objectList.push(parsePointLight(child as IPointLight));
|
|
|
+ } else if (type === 'Object3D') {
|
|
|
+ objectList.push(parseObject3D(child));
|
|
|
+ } else {
|
|
|
+ throw new Error('出现了未处理的类型:' + type);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- object3D.add(...objectList);
|
|
|
+ object3D.add(...objectList);
|
|
|
};
|
|
|
/**
|
|
|
* 生成动画
|
|
|
*/
|
|
|
-const genAnimations = (object3D: THREE.Object3D, sceneAnimations: IGroupParams["sceneAnimations"]) => {
|
|
|
- if (!sceneAnimations) return;
|
|
|
- const animations: THREE.AnimationClip[] = [];
|
|
|
-
|
|
|
- for (const animation of sceneAnimations!) {
|
|
|
- const clip = new THREE.AnimationClip(animation.name, animation.duration, [], animation.blendMode);
|
|
|
- //@ts-ignore
|
|
|
- for (const { name, times, values, type } of animation.tracks) {
|
|
|
- let nreTrack;
|
|
|
- if(type){
|
|
|
- if(type === 'vector') nreTrack = new THREE.VectorKeyframeTrack(name, times as any, values as any);
|
|
|
- if(type === 'quaternion') nreTrack = new THREE.QuaternionKeyframeTrack(name, times as any, values as any);
|
|
|
- }else {
|
|
|
- nreTrack = new THREE.QuaternionKeyframeTrack(name, times as any, values as any);
|
|
|
- }
|
|
|
-
|
|
|
- clip.tracks.push(nreTrack);
|
|
|
- }
|
|
|
-
|
|
|
- animations.push(clip);
|
|
|
+const genAnimations = (object3D: THREE.Object3D, sceneAnimations: IGroupParams['sceneAnimations']) => {
|
|
|
+ if (!sceneAnimations) return;
|
|
|
+ const animations: THREE.AnimationClip[] = [];
|
|
|
+
|
|
|
+ for (const animation of sceneAnimations!) {
|
|
|
+ const clip = new THREE.AnimationClip(animation.name, animation.duration, [], animation.blendMode);
|
|
|
+ //@ts-ignore
|
|
|
+ for (const { name, times, values, type } of animation.tracks) {
|
|
|
+ let nreTrack;
|
|
|
+ if (type) {
|
|
|
+ if (type === 'vector') nreTrack = new THREE.VectorKeyframeTrack(name, times as any, values as any);
|
|
|
+ if (type === 'quaternion') nreTrack = new THREE.QuaternionKeyframeTrack(name, times as any, values as any);
|
|
|
+ } else {
|
|
|
+ nreTrack = new THREE.QuaternionKeyframeTrack(name, times as any, values as any);
|
|
|
+ }
|
|
|
+
|
|
|
+ clip.tracks.push(nreTrack);
|
|
|
}
|
|
|
|
|
|
- object3D.animations = animations;
|
|
|
+ animations.push(clip);
|
|
|
+ }
|
|
|
+
|
|
|
+ object3D.animations = animations;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 解析传入的模型参数生成有效的three.js物体
|
|
|
*/
|
|
|
export const parseModel = (params: IGroupParams) => {
|
|
|
- const model = parseGroup(params);
|
|
|
- // model.position.x += 10;
|
|
|
- genAnimations(model, params.sceneAnimations);
|
|
|
- // console.log("解析完:", model);
|
|
|
- return model;
|
|
|
+ const model = parseGroup(params);
|
|
|
+ // model.position.x += 10;
|
|
|
+ genAnimations(model, params.sceneAnimations);
|
|
|
+ // console.log("解析完:", model);
|
|
|
+ return model;
|
|
|
};
|