parseModal.ts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import * as THREE from "three";
  2. import { THREEMaterialType, IBaseProps, IGroupParams, IMeshParams, IPointLight } from "./type/types";
  3. /**
  4. * glb模型并发加载工作原理
  5. * web worker 可以解析glb模型 但是postMessage发送的数据类型只是普通的对象,
  6. * 并且不能存在方法 方法无法传递,带方法会导致发送失败,并且不会触发onerror
  7. * THREE构建物体所需的bufferGeometry,还是BufferAttribute 或者Material等原型对象无法被传递
  8. * 传递到主线程的只是一个普通对象和上面的属性(对象中不能有函数)
  9. * 可以通过生成一个THREE所需的类型 把传递过来的对象上的参数复制给THREE需要的对象上
  10. * 这样在主线程生成一个同样的模型,但是省去了解析模型时间(模型解析在web worker中与js主线程并发执行)
  11. * 实现并发加载
  12. */
  13. /**
  14. * 通过设置attributes index来复刻一个集合体
  15. */
  16. const genGeometry = (geometry: IMeshParams["geometry"], IMeshParams) => {
  17. // console.log('目标------>',geometry);
  18. const geom = new THREE.BufferGeometry();
  19. const {
  20. attributes: { position, uv, normal },
  21. index,
  22. } = geometry;
  23. //处理几何坐标
  24. if(uv){
  25. const attributes = {
  26. position: new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
  27. uv: new THREE.BufferAttribute(uv.array, uv.itemSize, uv.normalized),
  28. normal: new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized),
  29. };
  30. geom.attributes = attributes;
  31. }else {
  32. const attributes = {
  33. position: new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
  34. normal: new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized),
  35. };
  36. // geom.attributes['position'] = new THREE.BufferAttribute(position.array, position.itemSize, position.normalized),
  37. // geom.attributes['normal'] = new THREE.BufferAttribute(normal.array, normal.itemSize, normal.normalized)
  38. geom.attributes = attributes;
  39. }
  40. geom.index = index ? new THREE.BufferAttribute(index.array, index.itemSize, index.normalized) : null;
  41. return geom;
  42. };
  43. /**
  44. * 根据传入纹理的参数生成真正有效的Material类型数据
  45. */
  46. const genMaterial = (mate: IMeshParams["material"]) => {
  47. if (!mate) return undefined;
  48. const multipleMaterial = Array.isArray(mate);
  49. const material = multipleMaterial ? ([] as THREE.Material[]) : new THREE[mate.type as THREEMaterialType]();
  50. //处理材质
  51. //多个材质
  52. if (multipleMaterial && Array.isArray(material)) {
  53. console.log('有多个材质');
  54. for (const m of mate) {
  55. const im = new THREE[m.type as THREEMaterialType]();
  56. material.push(im);
  57. }
  58. } else if (mate) {
  59. //单个材质
  60. Object.assign(material, mate);
  61. for (const key in mate) {
  62. if (Object.prototype.hasOwnProperty.call(mate, key)) {
  63. const element = mate[key];
  64. if(element && Object.prototype.toString.call(element === '[object Object]')) {
  65. if( element.isTexture){
  66. const texture = new THREE.Texture()
  67. for (const k in texture) {
  68. if(Object.prototype.toString.call(texture[k]) === '[object Object]'){
  69. if(k==='center' || k==='offset' || k==='repeat'){
  70. texture[k] = new THREE.Vector2()
  71. }
  72. if(k === 'matrix'){
  73. texture[k] = new THREE.Matrix3()
  74. }
  75. if(k === 'source'){
  76. texture[k] = new THREE.Source(null)
  77. }
  78. Object.assign(texture[k] , element[k]);
  79. }else {
  80. texture[k] = element[k]
  81. }
  82. }
  83. material[key] = texture
  84. }
  85. if(element.isColor){
  86. const color = new THREE.Color()
  87. Object.assign(color, element);
  88. material[key] = color
  89. }
  90. if(key === 'normalScale'){
  91. const vector2 = new THREE.Vector2()
  92. Object.assign(vector2, element);
  93. material[key] = vector2
  94. }
  95. }
  96. }
  97. }
  98. }
  99. return material;
  100. };
  101. /**
  102. * 处理基本属性转换(Object3D基类上的属性) matrix scale rotate translate position children animations
  103. */
  104. const parseBaseParams = (params: IBaseProps, object: THREE.Object3D) => {
  105. const matrix = new THREE.Matrix4();
  106. matrix.elements = params.matrix.elements;
  107. object.name = params.name;
  108. object.matrix = matrix;
  109. object.rotation.set(...params.rotation);
  110. object.position.set(...params.position);
  111. object.scale.set(...params.scale);
  112. object.quaternion.set(...params.quaternion);
  113. object.up.set(...params.up);
  114. object.userData = params.userData;
  115. object.visible = params.visible;
  116. parseChildren(object, params.children);
  117. genAnimations(object, params.animations);
  118. // deleteObjectKeys(params, [
  119. // "name",
  120. // "matrix",
  121. // "rotation",
  122. // "position",
  123. // "scale",
  124. // "quaternion",
  125. // "up",
  126. // "userData",
  127. // "visible",
  128. // ]);
  129. // object.scale.x += 0.3;
  130. // object.scale.y += 0.3;
  131. // object.scale.z += 0.3;
  132. };
  133. const parseMesh = (IMeshParams: IMeshParams) => {
  134. const geometry = genGeometry(IMeshParams.geometry, IMeshParams);
  135. const material = genMaterial(IMeshParams.material);
  136. const mesh = new THREE.Mesh(geometry, material);
  137. parseBaseParams(IMeshParams, mesh);
  138. return mesh;
  139. };
  140. const parseGroup = (params: IGroupParams) => {
  141. const group = new THREE.Group();
  142. parseBaseParams(params, group);
  143. return group;
  144. };
  145. const parsePointLight = (params: IPointLight) => {
  146. const color = new THREE.Color();
  147. // 色彩空间
  148. // export type ColorSpace = NoColorSpace | SRGBColorSpace | LinearSRGBColorSpace;
  149. // export type NoColorSpace = '';
  150. // export type SRGBColorSpace = 'srgb';
  151. // export type LinearSRGBColorSpace = 'srgb-linear';
  152. //glb模型为了亮度恢复 使用srgb格式 所以颜色也使用同样格式 使其颜色模式一致
  153. color.setRGB(params.color.r, params.color.g, params.color.b, "srgb-linear");
  154. const pointLight = new THREE.PointLight(color, params.intensity, params.distance, params.decay);
  155. parseBaseParams(params, pointLight);
  156. return pointLight;
  157. };
  158. const parseObject3D = (params: IBaseProps) => {
  159. const object = new THREE.Object3D();
  160. parseBaseParams(params, object);
  161. return object;
  162. };
  163. const parseChildren = (object3D: THREE.Object3D, children: IBaseProps[]) => {
  164. if (!children.length) return;
  165. const objectList: THREE.Object3D[] = [];
  166. for (const child of children) {
  167. const { type } = child;
  168. if (type === "Mesh") {
  169. objectList.push(parseMesh(child as IMeshParams));
  170. } else if (type === "Group") {
  171. objectList.push(parseGroup(child));
  172. } else if (type === "PointLight") {
  173. objectList.push(parsePointLight(child as IPointLight));
  174. } else if (type === "Object3D") {
  175. objectList.push(parseObject3D(child));
  176. } else {
  177. throw new Error("出现了未处理的类型:" + type);
  178. }
  179. }
  180. object3D.add(...objectList);
  181. };
  182. /**
  183. * 生成动画
  184. */
  185. const genAnimations = (object3D: THREE.Object3D, sceneAnimations: IGroupParams["sceneAnimations"]) => {
  186. if (!sceneAnimations) return;
  187. const animations: THREE.AnimationClip[] = [];
  188. for (const animation of sceneAnimations!) {
  189. const clip = new THREE.AnimationClip(animation.name, animation.duration, [], animation.blendMode);
  190. //@ts-ignore
  191. for (const { name, times, values, type } of animation.tracks) {
  192. let nreTrack;
  193. if(type){
  194. if(type === 'vector') nreTrack = new THREE.VectorKeyframeTrack(name, times as any, values as any);
  195. if(type === 'quaternion') nreTrack = new THREE.QuaternionKeyframeTrack(name, times as any, values as any);
  196. }else {
  197. nreTrack = new THREE.QuaternionKeyframeTrack(name, times as any, values as any);
  198. }
  199. clip.tracks.push(nreTrack);
  200. }
  201. animations.push(clip);
  202. }
  203. object3D.animations = animations;
  204. };
  205. /**
  206. * 解析传入的模型参数生成有效的three.js物体
  207. */
  208. export const parseModel = (params: IGroupParams) => {
  209. const model = parseGroup(params);
  210. // model.position.x += 10;
  211. genAnimations(model, params.sceneAnimations);
  212. // console.log("解析完:", model);
  213. return model;
  214. };