123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import * as THREE from "three";
- import { THREEMaterialType, IBaseProps, IGroupParams, IMeshParams, IPointLight } from "./type/types";
- /**
- * glb模型并发加载工作原理
- * web worker 可以解析glb模型 但是postMessage发送的数据类型只是普通的对象,
- * 并且不能存在方法 方法无法传递,带方法会导致发送失败,并且不会触发onerror
- * THREE构建物体所需的bufferGeometry,还是BufferAttribute 或者Material等原型对象无法被传递
- * 传递到主线程的只是一个普通对象和上面的属性(对象中不能有函数)
- * 可以通过生成一个THREE所需的类型 把传递过来的对象上的参数复制给THREE需要的对象上
- * 这样在主线程生成一个同样的模型,但是省去了解析模型时间(模型解析在web worker中与js主线程并发执行)
- * 实现并发加载
- */
- /**
- * 通过设置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;
- };
- /**
- * 根据传入纹理的参数生成真正有效的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);
- }
- } 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;
- };
- /**
- * 处理基本属性转换(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 parseMesh = (IMeshParams: IMeshParams) => {
- const geometry = genGeometry(IMeshParams.geometry, IMeshParams);
- const material = genMaterial(IMeshParams.material);
- 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 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 parseObject3D = (params: IBaseProps) => {
- 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);
- }
- }
- 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);
- }
- 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;
- };
|