threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

AGeometryGenerator.ts 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import {
  2. BufferAttribute,
  3. BufferGeometry,
  4. BufferGeometry2,
  5. Class,
  6. Float32BufferAttribute,
  7. generateUiConfig,
  8. getOrCall,
  9. IGeometry,
  10. UiObjectConfig,
  11. } from 'threepipe'
  12. declare module 'threepipe'{
  13. interface IGeometryUserData{
  14. generationParams?: {
  15. type: string
  16. // [key: string]: any
  17. }
  18. }
  19. }
  20. export interface GeometryGenerator<T=any>{
  21. generate(g?: IGeometry, parameters?: T): IGeometry
  22. createUiConfig?(geometry: IGeometry): UiObjectConfig[]
  23. }
  24. function updateAttribute<T extends BufferAttribute=Float32BufferAttribute>(geometry: BufferGeometry, attribute: string, itemSize: number, array: any[], cls?: Class<T>) {
  25. const attr = geometry.getAttribute(attribute) as T
  26. const count = array.length / itemSize
  27. if (attr && attr.count === count) {
  28. attr.set(array)
  29. attr.needsUpdate = true
  30. } else {
  31. geometry.setAttribute(attribute, new (cls ?? Float32BufferAttribute)(array, itemSize))
  32. }
  33. return attr
  34. }
  35. function updateIndices(geometry: BufferGeometry, indices: any[]) {
  36. const index = geometry.index
  37. if (index && index.count === indices.length) {
  38. index.set(indices)
  39. index.needsUpdate = true // todo: wireframe attribute is not updating
  40. } else geometry.setIndex(indices)
  41. }
  42. export function updateUi(geometry: BufferGeometry, childrenUi: () => UiObjectConfig[]) {
  43. if (!(geometry as any).uiConfig) return
  44. let oldUi = (geometry as any).uiConfig?.children?.find((c: UiObjectConfig) => c.tags?.includes('generatedGeometry'))
  45. if (!oldUi) {
  46. oldUi = {
  47. type: 'folder',
  48. label: 'Generation Params',
  49. tags: ['generatedGeometry'],
  50. children: [],
  51. }
  52. ;(geometry as any).uiConfig.children?.push(oldUi)
  53. }
  54. if (geometry.userData.__generationParamsUiType !== geometry.userData.generationParams.type) {
  55. oldUi.children = childrenUi()
  56. geometry.userData.__generationParamsUiType = geometry.userData.generationParams.type
  57. oldUi.uiRefresh?.('postFrame', true)
  58. }
  59. }
  60. export abstract class AGeometryGenerator<Tp=any> implements GeometryGenerator<Tp> {
  61. constructor(public type: string) {
  62. }
  63. abstract defaultParams: Tp
  64. createUiConfig(geometry: IGeometry): UiObjectConfig[] {
  65. if (!geometry.userData.generationParams) return []
  66. const ui = (generateUiConfig(geometry.userData.generationParams)
  67. // @ts-expect-error we assume only functions will be generated since its an object
  68. ?.map(v=>v())
  69. .filter(v=>getOrCall(v.property)?.[1] !== 'type') || []) as UiObjectConfig[]
  70. ui.forEach(u=> {
  71. u.onChange = () => this.generate(geometry)
  72. })
  73. return ui
  74. }
  75. protected abstract _generateData(params: Tp): {indices: number[]; vertices: number[]; normals: number[]; uvs: number[], groups?: {start: number, count: number, materialIndex: number}[]}
  76. generate(g?: IGeometry, parameters: Partial<Tp> = {}): IGeometry|BufferGeometry2 {
  77. const geometry: IGeometry = g ?? new BufferGeometry2()
  78. if (!geometry.userData.generationParams) geometry.userData.generationParams = {type: this.type}
  79. geometry.userData.generationParams.type = this.type
  80. if ((parameters as any).type) {
  81. console.error('Cannot change type of generated geometry here, use the plugin instead')
  82. return geometry
  83. }
  84. const params = {
  85. ...this.defaultParams,
  86. ...geometry.userData.generationParams,
  87. ...parameters,
  88. } as Tp
  89. const {indices, vertices, normals, uvs, groups} = this._generateData(params)
  90. // console.log(indices, vertices, normals, uvs, groups)
  91. updateIndices(geometry, indices)
  92. updateAttribute(geometry, 'position', 3, vertices)
  93. updateAttribute(geometry, 'normal', 3, normals)
  94. updateAttribute(geometry, 'uv', 2, uvs)
  95. if (groups) {
  96. geometry.clearGroups()
  97. for (const group of groups) {
  98. geometry.addGroup(group.start, group.count, group.materialIndex)
  99. }
  100. }
  101. geometry.computeBoundingBox()
  102. geometry.computeBoundingSphere()
  103. Object.assign(geometry.userData.generationParams, params)
  104. const childrenUi = ()=>this.createUiConfig(geometry)
  105. updateUi(geometry, childrenUi)
  106. geometry.setDirty()
  107. return geometry
  108. }
  109. }