@threepipe/plugin-blend-importer 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/BlendLoadPlugin.d.ts +1 -1
  2. package/dist/BlendLoadPlugin.d.ts.map +1 -1
  3. package/dist/dependencies.txt +32 -1
  4. package/dist/index.js +2179 -82
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +2179 -81
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/loader/bakeGetters.d.ts +2 -0
  9. package/dist/loader/bakeGetters.d.ts.map +1 -0
  10. package/dist/loader/camera.d.ts +4 -0
  11. package/dist/loader/camera.d.ts.map +1 -0
  12. package/dist/loader/ctx.d.ts +16 -0
  13. package/dist/loader/ctx.d.ts.map +1 -0
  14. package/dist/loader/geometry.d.ts +3 -2
  15. package/dist/loader/geometry.d.ts.map +1 -1
  16. package/dist/loader/index.d.ts +2 -1
  17. package/dist/loader/index.d.ts.map +1 -1
  18. package/dist/loader/light.d.ts +3 -2
  19. package/dist/loader/light.d.ts.map +1 -1
  20. package/dist/loader/material.d.ts +2 -2
  21. package/dist/loader/material.d.ts.map +1 -1
  22. package/dist/loader/mesh.d.ts +2 -2
  23. package/dist/loader/mesh.d.ts.map +1 -1
  24. package/package.json +2 -2
  25. package/src/BlendLoadPlugin.ts +42 -3
  26. package/src/js-blend/main.js +3 -2
  27. package/src/js-blend/parser/parser.js +152 -24
  28. package/src/js-blend/threejs/blend_three.js +1 -1
  29. package/src/js-blend/threejs/light.js +1 -1
  30. package/src/js-blend/threejs/material.js +1 -1
  31. package/src/loader/bakeGetters.ts +63 -0
  32. package/src/loader/camera.ts +55 -0
  33. package/src/loader/ctx.ts +29 -0
  34. package/src/loader/geometry.ts +236 -13
  35. package/src/loader/index.ts +95 -6
  36. package/src/loader/light.ts +18 -13
  37. package/src/loader/material.ts +7 -5
  38. package/src/loader/mesh.ts +14 -13
@@ -0,0 +1,55 @@
1
+ import {Object3D} from 'threepipe'
2
+ import {Ctx} from './ctx'
3
+
4
+ export function createCamera(object: any, ctx: Ctx): Object3D | undefined {
5
+ const cdata = object.data
6
+ // console.log(bakeGetters(object))
7
+ if (!cdata) return undefined
8
+
9
+ // Blender camera types: 0 = Perspective, 1 = Orthographic
10
+ const type = cdata.type
11
+ let camera: Object3D
12
+ if (type === 0) {
13
+ // Perspective
14
+ // Convert lens (mm) to field of view (fov) in degrees (vfov)
15
+ const sensorWidth = cdata.sensor_x || 36
16
+ const sensorHeight = cdata.sensor_y || 24
17
+ const lens = cdata.lens || 50
18
+ const fov = 2 * Math.atan(sensorHeight / (2 * lens)) * (180 / Math.PI)
19
+
20
+ camera = new ctx.PerspectiveCamera(
21
+ fov,
22
+ sensorWidth / sensorHeight,
23
+ cdata.clipsta || 0.1,
24
+ cdata.clipend || 1000
25
+ )
26
+ if ('shiftx' in cdata) camera.userData.shiftX = cdata.shiftx // todo?
27
+ if ('shiftx' in cdata) camera.userData.shiftX = cdata.shiftx // todo?
28
+ if ('shifty' in cdata) camera.userData.shiftY = cdata.shifty
29
+ } else if (type === 1) {
30
+ // Orthographic
31
+ const scale = cdata.ortho_scale || 1
32
+ const aspect = (cdata.sensor_x || 36) / (cdata.sensor_y || 24)
33
+ const left = -scale * aspect / 2
34
+ const right = scale * aspect / 2
35
+ const top = scale / 2
36
+ const bottom = -scale / 2
37
+ camera = new ctx.OrthographicCamera(
38
+ left, right, top, bottom,
39
+ cdata.clipsta || 0.1,
40
+ cdata.clipend || 1000
41
+ )
42
+ if ('shiftx' in cdata) camera.userData.shiftX = cdata.shiftx
43
+ if ('shifty' in cdata) camera.userData.shiftY = cdata.shifty
44
+ } else {
45
+ // Unknown camera type
46
+ camera = new ctx.PerspectiveCamera()
47
+ console.warn('Unsupported camera type', type)
48
+ }
49
+
50
+ // const obj = new Object3D()
51
+ // camera.rotation.x = -Math.PI / 2
52
+ // obj.add(camera)
53
+
54
+ return camera
55
+ }
@@ -0,0 +1,29 @@
1
+ import {
2
+ AmbientLight,
3
+ BufferAttribute,
4
+ BufferGeometry,
5
+ DirectionalLight,
6
+ Mesh,
7
+ MeshBasicMaterial,
8
+ MeshPhysicalMaterial,
9
+ Object3D,
10
+ OrthographicCamera,
11
+ PerspectiveCamera,
12
+ PointLight,
13
+ SpotLight,
14
+ } from 'threepipe'
15
+
16
+ export interface Ctx {
17
+ PointLight: typeof PointLight
18
+ SpotLight: typeof SpotLight
19
+ DirectionalLight: typeof DirectionalLight
20
+ AmbientLight: typeof AmbientLight
21
+ Object3D: typeof Object3D
22
+ PerspectiveCamera: typeof PerspectiveCamera
23
+ OrthographicCamera: typeof OrthographicCamera
24
+ Mesh: typeof Mesh
25
+ BufferGeometry: typeof BufferGeometry
26
+ BufferAttribute: typeof BufferAttribute
27
+ MeshPhysicalMaterial: typeof MeshPhysicalMaterial
28
+ MeshBasicMaterial: typeof MeshBasicMaterial
29
+ }
@@ -1,13 +1,227 @@
1
- import {BufferAttribute, BufferGeometry, Vector3Tuple} from 'threepipe'
1
+ import {Ctx} from './ctx'
2
2
 
3
- export function createBufferGeometry(mesh: any, origin: Vector3Tuple) {
3
+ function getLayer(layers: any, i: number) {
4
+ if (!Array.isArray(layers)) return layers
5
+ return layers[i]
6
+ }
7
+ // https://projects.blender.org/blender/blender/pulls/108015/files
8
+ // https://projects.blender.org/blender/blender/commit/1b63a290c68636211b16c5e212a699e6b63031b9
9
+ // https://developer.blender.org/docs/release_notes/4.0/python_api/#breaking-changes
10
+ // https://developer.blender.org/docs/release_notes/4.0/#blend-files
11
+ // https://projects.blender.org/blender/blender/commit/7966cd16d6dc4e66d01f7bd68a090107c1a7978c
12
+ // https://projects.blender.org/blender/blender/issues/95967
13
+ // https://projects.blender.org/blender/blender/pulls/106638
14
+
15
+ // https://github.com/blender/blender/blob/55e2fd2929b7577e0785c128c8f8069efd990c07/source/blender/blenkernel/intern/mesh.cc#L413
16
+ export function createBufferGeometry(meshData: any, ctx: Ctx) {
17
+
18
+ if (meshData.mpoly) return createBufferGeometryOld(meshData, ctx)
19
+ const geometry = new ctx.BufferGeometry()
20
+ geometry.name = meshData.aname || ''
21
+
22
+ // console.log(bakeGetters(meshData))
23
+
24
+ // https://github.com/blender/blender/blob/05dcc0377b62d8e026e1901dfbecbd4b06fda0b5/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_extract.py#L19
25
+
26
+ let vertices
27
+ let indices
28
+
29
+ // Extract vertex positions from vdata layers
30
+ if (meshData.vdata && meshData.vdata.layers && meshData.vdata.totlayer > 0) {
31
+ for (let i = 0; i < meshData.vdata.totlayer; i++) {
32
+ const layer = getLayer(meshData.vdata.layers, i)
33
+ // if (layer.type === 0) {
34
+ // https://github.com/blender/blender/blob/05dcc0377b62d8e026e1901dfbecbd4b06fda0b5/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_extract.py#L1575
35
+ const data = layer.data || []
36
+ // if (layer.name === 'position') { // type = 48 (custom vec3)
37
+ if (data.length === meshData.totvert) {
38
+ if (vertices && (layer.name !== 'position' || vertices.name === 'position')) {
39
+ // console.warn('BlendLoader - multiple vertices, ignoring', layer)
40
+ continue
41
+ }
42
+ vertices = layer
43
+ } else {
44
+ // console.log('unknown vdata', layer)
45
+ }
46
+ }
47
+ }
48
+
49
+ // Blender loops are indexes in three.js/blender. Called dots in gltf exporter
50
+
51
+ // // Extract indexes from loop data layers
52
+ if (meshData.ldata && meshData.ldata.layers) {
53
+ for (let i = 0; i < meshData.ldata.totlayer; i++) {
54
+ const layer = getLayer(meshData.ldata.layers, i)
55
+ // if (layer.type === 0) {
56
+ const data = layer.data || []
57
+ // if (layer.name === '.corner_vert') { // type = 11
58
+ if (data.length === meshData.totloop) { // type = 11
59
+ if (indices && (layer.name !== '.corner_vert' || indices.name === '.corner_vert')) {
60
+ // console.warn('BlendLoader - multiple indices, ignoring', layer)
61
+ continue
62
+ }
63
+ indices = layer
64
+ } else {
65
+ // console.log('unknown ldata', layer)
66
+ }
67
+ }
68
+ }
69
+ // if (meshData.pdata && meshData.pdata.layers) {
70
+ // for (let i = 0; i < meshData.pdata.totlayer; i++) {
71
+ // const layer = getLayer(meshData.pdata.layers, i)
72
+ // // if (layer.type === 0) {
73
+ // // if (layer.name === '.corner_vert') { // type = 11
74
+ // // } else {
75
+ // console.log('unknown pdata', layer)
76
+ // // }
77
+ // }
78
+ // }
79
+ // if (meshData.fdata && meshData.fdata.layers) {
80
+ // for (let i = 0; i < meshData.fdata.totlayer; i++) {
81
+ // const layer = getLayer(meshData.fdata.layers, i)
82
+ // // if (layer.type === 0) {
83
+ // // if (layer.name === '.corner_vert') { // type = 11
84
+ // // } else {
85
+ // console.log('unknown fdata', layer)
86
+ // // }
87
+ // }
88
+ // }
89
+ // if (meshData.edata && meshData.edata.layers) {
90
+ // for (let i = 0; i < meshData.edata.totlayer; i++) {
91
+ // const layer = getLayer(meshData.edata.layers, i)
92
+ // // if (layer.type === 0) {
93
+ // // if (layer.name === '.corner_vert') { // type = 11
94
+ // // } else {
95
+ // console.log('unknown edata', layer)
96
+ // // }
97
+ // }
98
+ // }
99
+
100
+ let faceIndices: number[] = []
101
+ if (meshData.poly_offset_indices && meshData.totpoly > 0) {
102
+ faceIndices = [...new Int32Array(meshData.poly_offset_indices.__blender_file__.AB, meshData.poly_offset_indices.__data_address__, meshData.totpoly + 1)]
103
+ }
104
+ // if (faceSize !== 3 && faceSize !== 4 && !faceIndices.length) {
105
+ // console.error('not supported polygons with ', faceSize, 'vertices')
106
+ // return geometry
107
+ // }
108
+
109
+ if (vertices?.data && vertices.data.length > 0) {
110
+ const positions = new Float32Array(vertices.data.length * 3)
111
+ for (let j = 0; j < vertices.data.length; j++) {
112
+ const vertex = vertices.data[j]
113
+ if (vertex.x !== undefined) {
114
+ positions[j * 3] = vertex.x
115
+ positions[j * 3 + 1] = vertex.z
116
+ positions[j * 3 + 2] = -vertex.y
117
+ } else if (vertex.co !== undefined) {
118
+ positions[j * 3] = vertex.co[0]
119
+ positions[j * 3 + 1] = vertex.co[2]
120
+ positions[j * 3 + 2] = -vertex.co[1]
121
+ } else {
122
+ // console.log(bakeGetters(meshData))
123
+ // const t = [...new Int32Array(vertex.__blender_file__.AB, vertex.__data_address__, 8)]
124
+ // debugger
125
+ console.error('BlendLoader - unknown vertex', vertex)
126
+ break
127
+ }
128
+ }
129
+ geometry.setAttribute('position', new ctx.BufferAttribute(positions, 3))
130
+ }
131
+
132
+ if (indices?.data && indices.data.length > 0 && vertices?.data?.length) {
133
+ const faceSize = meshData.totloop / meshData.totpoly
134
+ if (faceIndices.length > 0) {
135
+ // Use face offset indices for variable-sized faces
136
+ let totalTriangles = 0
137
+ for (let i = 0; i < faceIndices.length - 1; i++) {
138
+ const faceVertCount = faceIndices[i + 1] - faceIndices[i]
139
+ totalTriangles += Math.max(0, faceVertCount - 2)
140
+ }
141
+
142
+ const indexes = new Uint32Array(totalTriangles * 3)
143
+ let t = 0
144
+
145
+ for (let i = 0; i < faceIndices.length - 1; i++) {
146
+ const faceStart = faceIndices[i]
147
+ const faceEnd = faceIndices[i + 1]
148
+ const faceVertCount = faceEnd - faceStart
149
+
150
+ if (faceVertCount >= 3) {
151
+ // todo better Triangulate the face using fan triangulation
152
+ const firstVert = indices.data[faceStart].i
153
+ for (let k = 1; k < faceVertCount - 1; k++) {
154
+ indexes[t++] = firstVert
155
+ indexes[t++] = indices.data[faceStart + k].i
156
+ indexes[t++] = indices.data[faceStart + k + 1].i
157
+ }
158
+ } else {
159
+ // debugger
160
+ }
161
+ }
162
+
163
+ // console.log(indexes)
164
+ geometry.setIndex(new ctx.BufferAttribute(indexes, 1))
165
+ } else if (faceSize === 3 || faceSize === 4) {
166
+ // Fall back to uniform face size approach
167
+ const isQuad = faceSize === 4
168
+ const faceCount = indices.length / faceSize
169
+ const indexes = new Uint32Array(faceCount * 3 * (isQuad ? 2 : 1))
170
+
171
+ if (faceSize !== 3 && faceSize !== 4) return geometry
172
+ for (let j = 0, t = 0; j < indices.length; j += faceSize) {
173
+ const a = indices[j].i
174
+ const b = indices[j + 1].i
175
+ const c = indices[j + 2].i
176
+ indexes[t++] = a
177
+ indexes[t++] = b
178
+ indexes[t++] = c
179
+
180
+ if (isQuad) {
181
+ const d = indices[j + 3].i
182
+ indexes[t++] = a
183
+ indexes[t++] = c
184
+ indexes[t++] = d
185
+ }
186
+ }
187
+ geometry.setIndex(new ctx.BufferAttribute(indexes, 1))
188
+ }
189
+ } else if (faceIndices) {
190
+ console.error('BlendLoader - no indices data found, but face indices are present', faceIndices)
191
+ }
192
+
193
+ // console.log(geometry.attributes.position)
194
+ // console.log(geometry.index)
195
+
196
+ // compute stuff not present
197
+ if (geometry.attributes.position && !geometry.attributes.normal)
198
+ geometry.computeVertexNormals()
199
+
200
+ // if (meshData.loc) { // maybe this is the bbox center?
201
+ // geometry.translate(meshData.loc[0], meshData.loc[2], -meshData.loc[1])
202
+ // }
203
+ // if (meshData.size) { // maybe this is the bbox size?
204
+ // geometry.scale(meshData.size[0], meshData.size[2], -meshData.size[1])
205
+ // }
206
+
207
+ return geometry
208
+ }
209
+ // // https://github.com/blender/blender/blob/05dcc0377b62d8e026e1901dfbecbd4b06fda0b5/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_extract.py#L19
210
+ // // https://github.com/blender/blender/blob/05dcc0377b62d8e026e1901dfbecbd4b06fda0b5/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_extract.py#L1575
211
+ // // todo __set_morph_locs_attribute
212
+ // // todo __set_morph_tangent_attribute
213
+ // // todo pdata(points), edata(edge), fdata(face? legacy?)
214
+ // // meshData.eData = domain edge - https://github.com/blender/blender/blob/05dcc0377b62d8e026e1901dfbecbd4b06fda0b5/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_extract.py#L189
215
+ // // todo normals, tangents
216
+
217
+ export function createBufferGeometryOld(mesh: any, ctx: Ctx) {
4
218
  const
5
219
  faces = Array.isArray(mesh.mpoly) ? mesh.mpoly as any[] : [mesh.mpoly],
6
220
  loops = mesh.mloop,
7
221
  uv = mesh.mloopuv,
8
222
  vertices = mesh.mvert
9
223
 
10
- const geometry = new BufferGeometry()
224
+ const geometry = new ctx.BufferGeometry()
11
225
 
12
226
  if (!faces) return geometry
13
227
 
@@ -18,6 +232,7 @@ export function createBufferGeometry(mesh: any, origin: Vector3Tuple) {
18
232
  const positions = new Float32Array(size * 3)
19
233
 
20
234
  let currentIndex = 0
235
+ let computeNormals = false
21
236
 
22
237
  for (const face of faces) {
23
238
  const len = face.totloop
@@ -39,13 +254,17 @@ export function createBufferGeometry(mesh: any, origin: Vector3Tuple) {
39
254
  const vert = vertices[loop.v]
40
255
  indices[currentIndex] = currentIndex
41
256
 
42
- positions[currentIndex * 3 + 0] = vert.co[0] + origin[0]
43
- positions[currentIndex * 3 + 1] = vert.co[2] + origin[2]
44
- positions[currentIndex * 3 + 2] = -vert.co[1] + -origin[1]
257
+ positions[currentIndex * 3 + 0] = vert.co[0]
258
+ positions[currentIndex * 3 + 1] = vert.co[2]
259
+ positions[currentIndex * 3 + 2] = -vert.co[1]
45
260
 
46
- normals[currentIndex * 3 + 0] = vert.no[0]
47
- normals[currentIndex * 3 + 1] = vert.no[2]
48
- normals[currentIndex * 3 + 2] = -vert.no[1]
261
+ if (vert.no) {
262
+ normals[currentIndex * 3 + 0] = vert.no[0]
263
+ normals[currentIndex * 3 + 1] = vert.no[2]
264
+ normals[currentIndex * 3 + 2] = -vert.no[1]
265
+ } else {
266
+ computeNormals = true
267
+ }
49
268
 
50
269
  if (uv) {
51
270
  uvs[currentIndex * 2 + 0] = uv[index].uv[0]
@@ -59,10 +278,14 @@ export function createBufferGeometry(mesh: any, origin: Vector3Tuple) {
59
278
  }
60
279
  }
61
280
 
62
- geometry.setAttribute('position', new BufferAttribute(positions, 3))
63
- geometry.setIndex(new BufferAttribute(indices, 1))
64
- geometry.setAttribute('normal', new BufferAttribute(normals, 3))
65
- geometry.setAttribute('uv', new BufferAttribute(uvs, 2))
281
+ geometry.setAttribute('position', new ctx.BufferAttribute(positions, 3))
282
+ geometry.setIndex(new ctx.BufferAttribute(indices, 1))
283
+ geometry.setAttribute('normal', new ctx.BufferAttribute(normals, 3))
284
+ geometry.setAttribute('uv', new ctx.BufferAttribute(uvs, 2))
285
+
286
+ if (computeNormals) {
287
+ geometry.computeVertexNormals()
288
+ }
66
289
 
67
290
  return geometry
68
291
  }
@@ -1,26 +1,115 @@
1
+ import {createCamera} from './camera'
1
2
  import {createLight} from './light'
2
3
  import {createMesh} from './mesh'
3
- import {Object3D} from 'threepipe'
4
+ import {IObject3D, Object3D} from 'threepipe'
5
+ import {Ctx} from './ctx'
6
+ import {Euler, EulerOrder} from 'three/src/math/Euler'
7
+ import {Quaternion, Vector3} from 'three'
4
8
 
9
+ // https://github.com/blender/blender/blob/99a4c93081cc2310a09a14f20a1493e8974c10d2/source/blender/makesdna/DNA_object_types.h#L445
5
10
  const blenderObjectTypes = {
11
+ empty: 0,
6
12
  mesh: 1,
7
13
  lamp: 10,
14
+ camera: 11,
8
15
  }
9
16
 
10
- export async function createObjects(file: any) {
17
+ export async function createObjects(file: any, ctx: Ctx) {
11
18
  const objects: (Object3D|null)[] = []
12
- const blendObjects = file.objects.Object
19
+ const childMap = new Map<any, Object3D[]>()
20
+ const objMap = new Map<any, Object3D>()
21
+ const blendObjects = file.objects.Object ?? []
22
+ const loaded = new WeakMap()
23
+ // console.log(bakeGetters(file))
13
24
  for (const object of blendObjects) {
25
+ if (loaded.has(object)) {
26
+ console.warn('BlendLoader - duplicate object')
27
+ continue
28
+ }
29
+ let obj: Object3D | undefined = undefined
14
30
  switch (object.type) {
31
+ case blenderObjectTypes.empty:
32
+ obj = new ctx.Object3D()
33
+ break
15
34
  case blenderObjectTypes.mesh:
16
- objects.push(createMesh(object))
35
+ obj = createMesh(object, loaded, ctx)
17
36
  break
18
37
  case blenderObjectTypes.lamp:
19
- objects.push(createLight(object))
38
+ obj = createLight(object, ctx)
39
+ break
40
+ case blenderObjectTypes.camera:
41
+ obj = createCamera(object, ctx)
20
42
  break
21
43
  default:
22
- console.warn('Unsupported object type', object.type)
44
+ obj = new ctx.Object3D()
45
+ console.warn('Unsupported object type', object.type, object, obj)
46
+ }
47
+ if (obj) {
48
+ setTransform(object, obj as any)
49
+ const exChildren = childMap.get(object)
50
+ if (exChildren) {
51
+ for (const exChild of exChildren) {
52
+ obj.add(exChild)
53
+ }
54
+ childMap.delete(object)
55
+ }
56
+ objMap.set(object, obj)
57
+ if (object.parent === object) {
58
+ console.error('BlendLoader - invalid, parent same as object, adding to root', object)
59
+ objects.push(obj)
60
+ } else if (!object.parent) { // just in case
61
+ objects.push(obj)
62
+ } else {
63
+ const parent = objMap.get(object.parent)
64
+ if (!parent) {
65
+ const chi = childMap.get(object.parent) ?? []
66
+ chi.push(obj)
67
+ childMap.set(object, chi)
68
+ } else {
69
+ parent.add(obj)
70
+ }
71
+ }
72
+ loaded.set(object, obj)
23
73
  }
24
74
  }
75
+ if (childMap.size) {
76
+ const vals = [...childMap.values()].flat()
77
+ console.warn('BlendLoader - unknown objects with parents, adding to root', vals, childMap)
78
+ objects.push(...vals)
79
+ }
25
80
  return objects.filter(o => !!o) as Object3D[]
26
81
  }
82
+
83
+
84
+ // https://github.com/blender/blender/blob/458e224587e8c45da20841a283cc1b41adc98950/source/blender/makesdna/DNA_action_types.h#L526
85
+ const eulerModes: Record<number, EulerOrder> = {
86
+ [1]: 'XYZ',
87
+ [2]: 'XZY',
88
+ [3]: 'YXZ',
89
+ [4]: 'YZX',
90
+ [5]: 'ZXY',
91
+ [6]: 'ZYX',
92
+ }
93
+
94
+ function setTransform(object: any, obj: IObject3D) {
95
+ obj.name = object.aname
96
+ obj.scale.set(object.size[0], object.size[2], object.size[1])
97
+ obj.position.set(object.loc[0], object.loc[2], -object.loc[1])
98
+
99
+ if (!object.rotmode || object.rotmode === 0) {
100
+ // const quat = new Quaternion()
101
+ obj.quaternion.set(object.quat[1], object.quat[3], -object.quat[2], object.quat[0]) // wxyz
102
+ } else {
103
+ // console.log(object.rotmode)
104
+ // const order = eulerModes[4]
105
+ const order = eulerModes[object.rotmode] ?? 'XYZ'
106
+ const quat = new Quaternion().setFromEuler(new Euler(object.rot[0], object.rot[1], object.rot[2], order.split('').reverse().join('') as any))
107
+ obj.quaternion.set(quat.x, quat.z, -quat.y, quat.w) // wxyz
108
+ }
109
+ // because camera is rotated 90d in blender
110
+ if (object.type === blenderObjectTypes.camera)
111
+ obj.quaternion.multiply(new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2))
112
+
113
+ obj.updateMatrix()
114
+ if (obj.setDirty) obj.setDirty()
115
+ }
@@ -1,4 +1,5 @@
1
- import {PointLight} from 'threepipe'
1
+ import {Light} from 'threepipe'
2
+ import {Ctx} from './ctx'
2
3
 
3
4
  const blenderLightTypes = {
4
5
  point: 0,
@@ -8,7 +9,7 @@ const blenderLightTypes = {
8
9
  area: 0,
9
10
  }
10
11
 
11
- export function createLight(lamp: any) {
12
+ export function createLight(lamp: any, ctx: Ctx) {
12
13
  const ldata = lamp.data
13
14
 
14
15
  const position = [lamp.loc[0], lamp.loc[2], -lamp.loc[1]]
@@ -17,22 +18,26 @@ export function createLight(lamp: any) {
17
18
  const intensity = ldata.energy
18
19
  const distance = 0
19
20
 
20
- let light = null
21
+ let light: Light | undefined = undefined
21
22
 
22
23
  switch (ldata.type) {
23
24
  case blenderLightTypes.point:
24
- light = new PointLight(color, intensity, distance)
25
- light.position.fromArray(position, 0)
26
- light.castShadow = true
25
+ light = new ctx.PointLight(color, intensity, distance)
26
+ light!.position.fromArray(position, 0)
27
+ light!.castShadow = true
27
28
  break
28
29
  case blenderLightTypes.sun:
29
- light = new PointLight(color, intensity, distance)
30
- light.position.fromArray(position, 0)
31
- light.castShadow = true
32
- light.shadow.mapSize.width = 1024
33
- light.shadow.mapSize.height = 1024
34
- light.shadow.camera.near = 0.01
35
- light.shadow.camera.far = 500
30
+ light = new ctx.PointLight(color, intensity, distance)
31
+ light!.position.fromArray(position, 0)
32
+ light!.castShadow = true
33
+ if (light!.shadow) {
34
+ light!.shadow.mapSize.width = 1024
35
+ light!.shadow.mapSize.height = 1024
36
+ // @ts-expect-error ??/
37
+ light!.shadow.camera.near = 0.01
38
+ // @ts-expect-error ??/
39
+ light!.shadow.camera.far = 500
40
+ }
36
41
  break
37
42
  default:
38
43
  console.warn('Unsupported light type', ldata.type)
@@ -1,12 +1,14 @@
1
- import {MeshPhysicalMaterial} from 'threepipe'
2
-
3
1
  // todo see blender gltf exporter and convert to js. structure is the same
4
- export function createMaterial(mat: any) {
5
- const material = new MeshPhysicalMaterial()
2
+ // https://github.com/KhronosGroup/glTF-Blender-IO/blob/ed5100ab6c40472b7c3254fddfe0dd0d76d60644/addons/io_scene_gltf2/blender/exp/material/materials.py#L60
3
+ import {Ctx} from './ctx'
4
+
5
+ export function createMaterial(mat: any, ctx: Ctx) {
6
+ const material = new ctx.MeshPhysicalMaterial()
6
7
  material.color.setRGB(mat.r, mat.g, mat.b)
7
8
  material.roughness = mat.roughness !== undefined ? mat.roughness : 0.4
8
9
  material.metalness = mat.metallic !== undefined ? mat.metallic : 0.0
9
- material.opacity = mat.alpha !== undefined ? mat.alpha : 0.0
10
+ // material.opacity = mat.alpha !== undefined ? mat.alpha : 0.0
11
+ material.opacity = 1
10
12
  material.transparent = material.opacity < 1.0
11
13
  return material
12
14
  }
@@ -1,26 +1,27 @@
1
- import {Mesh} from 'threepipe'
2
1
  import {createBufferGeometry} from './geometry'
3
2
  import {createMaterial} from './material'
3
+ import {Ctx} from './ctx'
4
4
 
5
- export function createMesh(object: any) {
6
- if (!object.data) return null
5
+ export function createMesh(object: any, loaded: WeakMap<any, any>, ctx: Ctx) {
6
+ if (!object.data) {
7
+ return undefined
8
+ }
7
9
 
8
- const geometry = createBufferGeometry(object.data, [0, 0, 0])
10
+ const geometry = loaded.get(object.data) ?? createBufferGeometry(object.data, ctx)
11
+ loaded.set(object.data, geometry)
9
12
 
10
13
  const mat = object.data.mat[0]
11
14
 
12
- const material = mat ? createMaterial(mat) : undefined
13
- const mesh = new Mesh(geometry, material)
15
+ // const material = mat ? createMaterial(mat) : undefined
16
+ const material = mat ? loaded.get(mat) ?? createMaterial(mat, ctx) : new ctx.MeshPhysicalMaterial()
17
+ if (mat) loaded.set(mat, material)
18
+
19
+ // console.log(material, mat)
20
+ // material.side = DoubleSide
21
+ const mesh = new ctx.Mesh(geometry, material)
14
22
 
15
23
  mesh.castShadow = true
16
24
  mesh.receiveShadow = true
17
25
 
18
- mesh.rotateZ(object.rot[2])
19
- mesh.rotateY(object.rot[1])
20
- mesh.rotateX(object.rot[0])
21
-
22
- mesh.scale.fromArray(object.size, 0)
23
- mesh.position.fromArray([object.loc[0], object.loc[2], -object.loc[1]], 0)
24
-
25
26
  return mesh
26
27
  }