comparison semiconginev2/gltf.nim @ 1248:317bb5a73606

did: continue on gltf importer
author sam <sam@basx.dev>
date Thu, 25 Jul 2024 20:23:54 +0700
parents c15770761865
children d83726af7abb
comparison
equal deleted inserted replaced
1247:c15770761865 1248:317bb5a73606
1 type 1 type
2 GLTFMesh*[TMesh, TMaterial] = object 2 GLTFMesh*[TMesh, TMaterial] = object
3 scenes*: seq[seq[int]] # each scene has a seq of node indices 3 scenes*: seq[seq[int]] # each scene has a seq of node indices
4 nodes*: seq[seq[int]] # each node has a seq of mesh indices 4 nodes*: seq[seq[int]] # each node has a seq of mesh indices
5 meshes*: seq[TMesh] 5 meshes*: seq[seq[(TMesh, VkPrimitiveTopology)]]
6 materials*: seq[TMaterial] 6 materials*: seq[TMaterial]
7 textures*: seq[Image[BGRA]] 7 textures*: seq[Image[BGRA]]
8 glTFHeader = object 8 glTFHeader = object
9 magic: uint32 9 magic: uint32
10 version: uint32 10 version: uint32
11 length: uint32 11 length: uint32
12 glTFData = object 12 glTFData = object
13 structuredContent: JsonNode 13 structuredContent: JsonNode
14 binaryBufferData: seq[uint8] 14 binaryBufferData: seq[uint8]
15 15
16 MaterialAttributeNames = object 16 MaterialAttributeNames* = object
17 # pbr 17 # pbr
18 baseColorTexture: string 18 baseColorTexture*: string
19 baseColorTextureUv: string 19 baseColorTextureUv*: string
20 baseColorFactor: string 20 baseColorFactor*: string
21 metallicRoughnessTexture: string 21 metallicRoughnessTexture*: string
22 metallicRoughnessTextureUv: string 22 metallicRoughnessTextureUv*: string
23 metallicFactor: string 23 metallicFactor*: string
24 roughnessFactor: string 24 roughnessFactor*: string
25 25
26 # other 26 # other
27 normalTexture: string 27 normalTexture*: string
28 normalTextureUv: string 28 normalTextureUv*: string
29 occlusionTexture: string 29 occlusionTexture*: string
30 occlusionTextureUv: string 30 occlusionTextureUv*: string
31 emissiveTexture: string 31 emissiveTexture*: string
32 emissiveTextureUv: string 32 emissiveTextureUv*: string
33 emissiveFactor: string 33 emissiveFactor*: string
34
35 MeshAttributeNames* = object
36 POSITION*: string
37 NORMAL*: string
38 TANGENT*: string
39 TEXCOORD*: seq[string]
40 COLOR*: seq[string]
41 JOINTS*: seq[string]
42 WEIGHTS*: seq[string]
43 indices*: string
44 material*: string
34 45
35 #[ 46 #[
36 static: 47 static:
37 let TypeIds = { 48 let TypeIds = {
38 int8: 5120, 49 int8: 5120,
69 SAMPLER_WRAP_MODE_MAP = { 80 SAMPLER_WRAP_MODE_MAP = {
70 33071: VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 81 33071: VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
71 33648: VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, 82 33648: VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
72 10497: VK_SAMPLER_ADDRESS_MODE_REPEAT 83 10497: VK_SAMPLER_ADDRESS_MODE_REPEAT
73 }.toTable 84 }.toTable
85 PRIMITIVE_MODE_MAP = [
86 0: VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
87 1: VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
88 2: VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, # not correct, as mode 2 would be a loo, but vulkan has no concept of this
89 3: VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
90 4: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
91 5: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
92 6: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
93 ]
74 94
75 #[ 95 #[
76 proc getGPUType(accessor: JsonNode, attribute: string): DataType = 96 proc getGPUType(accessor: JsonNode, attribute: string): DataType =
77 # TODO: no full support for all datatypes that glTF may provide 97 # TODO: no full support for all datatypes that glTF may provide
78 # semicongine/core/gpu_data should maybe generated with macros to allow for all combinations 98 # semicongine/core/gpu_data should maybe generated with macros to allow for all combinations
119 139
120 if bufferView.hasKey("byteStride"): 140 if bufferView.hasKey("byteStride"):
121 raise newException(Exception, "Unsupported feature: byteStride in buffer view") 141 raise newException(Exception, "Unsupported feature: byteStride in buffer view")
122 copyMem(dstPointer, addr mainBuffer[bufferOffset], result.len) 142 copyMem(dstPointer, addr mainBuffer[bufferOffset], result.len)
123 143
124 #[ 144 proc getAccessorData[T](root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): seq[T] =
125 proc getAccessorData(root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): DataList = 145 result.setLen(accessor["count"].getInt())
126 result = InitDataList(thetype = accessor.getGPUType("??"))
127 result.SetLen(accessor["count"].getInt())
128 146
129 let bufferView = root["bufferViews"][accessor["bufferView"].getInt()] 147 let bufferView = root["bufferViews"][accessor["bufferView"].getInt()]
130 assert bufferView["buffer"].getInt() == 0, "Currently no external buffers supported" 148 assert bufferView["buffer"].getInt() == 0, "Currently no external buffers supported"
131 149
132 if accessor.hasKey("sparse"): 150 if accessor.hasKey("sparse"):
133 raise newException(Exception, "Sparce accessors are currently not implemented") 151 raise newException(Exception, "Sparce accessors are currently not supported")
134 152
135 let accessorOffset = if accessor.hasKey("byteOffset"): accessor["byteOffset"].getInt() else: 0 153 let accessorOffset = if accessor.hasKey("byteOffset"): accessor["byteOffset"].getInt() else: 0
136 let length = bufferView["byteLength"].getInt() 154 let length = bufferView["byteLength"].getInt()
137 let bufferOffset = bufferView["byteOffset"].getInt() + accessorOffset 155 let bufferOffset = bufferView["byteOffset"].getInt() + accessorOffset
138 var dstPointer = result.GetPointer() 156 var dstPointer = result.ToCPointer()
139 157
140 if bufferView.hasKey("byteStride"): 158 if bufferView.hasKey("byteStride"):
141 warn "Congratulations, you try to test a feature (loading buffer data with stride attributes) that we have no idea where it is used and how it can be tested (need a coresponding *.glb file)." 159 warn "Congratulations, you try to test a feature (loading buffer data with stride attributes) that we have no idea where it is used and how it can be tested (need a coresponding *.glb file)."
142 # we don't support stride, have to convert stuff here... does this even work? 160 # we don't support stride, have to convert stuff here... does this even work?
143 for i in 0 ..< int(result.len): 161 for i in 0 ..< int(result.len):
144 copyMem(dstPointer, addr mainBuffer[bufferOffset + i * bufferView["byteStride"].getInt()], int(result.thetype.Size)) 162 copyMem(dstPointer, addr mainBuffer[bufferOffset + i * bufferView["byteStride"].getInt()], result.len * sizeof(T))
145 dstPointer = cast[pointer](cast[uint](dstPointer) + result.thetype.Size) 163 dstPointer = cast[typeof(dstPointer)](cast[uint](dstPointer) + (result.len * sizeof(T)).uint)
146 else: 164 else:
147 copyMem(dstPointer, addr mainBuffer[bufferOffset], length) 165 copyMem(dstPointer, addr mainBuffer[bufferOffset], length)
148 ]#
149 166
150 proc loadTexture(root: JsonNode, textureNode: JsonNode, mainBuffer: seq[uint8]): Image[BGRA] = 167 proc loadTexture(root: JsonNode, textureNode: JsonNode, mainBuffer: seq[uint8]): Image[BGRA] =
151 168
152 let imageIndex = textureNode["source"].getInt() 169 let imageIndex = textureNode["source"].getInt()
153 170
195 elif gltfAttribute in ["metallicFactor", "roughnessFactor"]: 212 elif gltfAttribute in ["metallicFactor", "roughnessFactor"]:
196 value = pbr[gltfAttribute].getFloat() 213 value = pbr[gltfAttribute].getFloat()
197 else: 214 else:
198 {.error: "Unsupported gltf material attribute".} 215 {.error: "Unsupported gltf material attribute".}
199 216
217 proc loadPrimitive[TMesh](root: JsonNode, primitive: JsonNode, mapping: static MeshAttributeNames, mainBuffer: seq[uint8]): (TMesh, VkPrimitiveTopology) =
218 result[0] = TMesh()
219 result[1] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
220 if primitive.hasKey("mode"):
221 result[1] = PRIMITIVE_MODE_MAP[primitive["mode"].getInt()]
222
223 for name, value in fieldPairs(result[0]):
224 for gltfAttribute, mappedName in fieldPairs(mapping):
225 when gltfAttribute != "" and name == mappedName:
226 assert value is GPUData, "Attribute " & name & " must be of type GPUData"
227 #[
228 when gltfAttribute == "indices":
229 if primitive.hasKey(gltfAttribute):
230 let accessor = primitive[gltfAttribute].getInt()
231 value.data = getAccessorData[elementType(value.data)](root, root["accessors"][accessor], mainBuffer)
232 elif gltfAttribute == "material":
233 if primitive.hasKey(gltfAttribute):
234 value.data = typeof(value.data)(primitive[gltfAttribute].getInt())
235 else:
236 if primitive["attributes"].hasKey(gltfAttribute):
237 let accessor = primitive["attributes"][gltfAttribute].getInt()
238 value.data = getAccessorData[elementType(value.data)](root, root["accessors"][accessor], mainBuffer)
239 ]#
240
241 #[
242 var indexType = None
243 let indexed = primitive.hasKey("indices")
244 if indexed:
245 var indexCount = root["accessors"][primitive["indices"].getInt()]["count"].getInt()
246 if indexCount < int(high(uint16)):
247 indexType = Small
248 else:
249 indexType = Big
250
251 for attribute, accessor in primitive["attributes"].pairs:
252 let data = root.getAccessorData(root["accessors"][accessor.getInt()], mainBuffer)
253 if result.vertexCount == 0:
254 result.vertexCount = data.len
255 assert data.len == result.vertexCount
256 result[].InitVertexAttribute(attribute.toLowerAscii, data)
257
258 if primitive.hasKey("material"):
259 let materialId = primitive["material"].getInt()
260 result[].material = materials[materialId]
261 else:
262 result[].material = EMPTY_MATERIAL.InitMaterialData()
263
264 if primitive.hasKey("indices"):
265 assert result[].indexType != None
266 let data = root.getAccessorData(root["accessors"][primitive["indices"].getInt()], mainBuffer)
267 var tri: seq[int]
268 case data.thetype
269 of UInt16:
270 for entry in data[uint16][]:
271 tri.add int(entry)
272 if tri.len == 3:
273 # FYI gltf uses counter-clockwise indexing
274 result[].AppendIndicesData(tri[0], tri[1], tri[2])
275 tri.setLen(0)
276 of UInt32:
277 for entry in data[uint32][]:
278 tri.add int(entry)
279 if tri.len == 3:
280 # FYI gltf uses counter-clockwise indexing
281 result[].AppendIndicesData(tri[0], tri[1], tri[2])
282 tri.setLen(0)
283 else:
284 raise newException(Exception, &"Unsupported index data type: {data.thetype}")
285 ]#
286
200 287
201 #[ 288 #[
202 289
203 proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = 290 proc loadPrimitive(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh =
204 if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: 291 if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4:
205 raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode") 292 raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode")
206 293
207 var indexType = None 294 var indexType = None
208 let indexed = primitiveNode.hasKey("indices") 295 let indexed = primitiveNode.hasKey("indices")
263 result = MeshTree() 350 result = MeshTree()
264 # mesh 351 # mesh
265 if node.hasKey("mesh"): 352 if node.hasKey("mesh"):
266 let mesh = root["meshes"][node["mesh"].getInt()] 353 let mesh = root["meshes"][node["mesh"].getInt()]
267 for primitive in mesh["primitives"]: 354 for primitive in mesh["primitives"]:
268 result.children.add MeshTree(mesh: loadMesh(mesh["name"].getStr(), root, primitive, materials, mainBuffer)) 355 result.children.add MeshTree(mesh: loadPrimitive(mesh["name"].getStr(), root, primitive, materials, mainBuffer))
269 356
270 # transformation 357 # transformation
271 if node.hasKey("matrix"): 358 if node.hasKey("matrix"):
272 var mat: Mat4 359 var mat: Mat4
273 for i in 0 ..< node["matrix"].len: 360 for i in 0 ..< node["matrix"].len:
314 401
315 ]# 402 ]#
316 403
317 proc ReadglTF*[TMesh, TMaterial]( 404 proc ReadglTF*[TMesh, TMaterial](
318 stream: Stream, 405 stream: Stream,
319 baseColorFactor: static string = "", 406 meshAttributesMapping: static MeshAttributeNames,
320 emissiveFactor: static string = "", 407 materialAttributesMapping: static MaterialAttributeNames,
321 metallicFactor: static string = "",
322 roughnessFactor: static string = "",
323 baseColorTexture: static string = "",
324 metallicRoughnessTexture: static string = "",
325 normalTexture: static string = "",
326 occlusionTexture: static string = "",
327 emissiveTexture: static string = "",
328 ): GLTFMesh[TMesh, TMaterial] = 408 ): GLTFMesh[TMesh, TMaterial] =
329 const mapping = MaterialAttributeNames(
330 baseColorFactor: baseColorFactor,
331 emissiveFactor: emissiveFactor,
332 metallicFactor: metallicFactor,
333 roughnessFactor: roughnessFactor,
334 baseColorTexture: baseColorTexture,
335 metallicRoughnessTexture: metallicRoughnessTexture,
336 normalTexture: normalTexture,
337 occlusionTexture: occlusionTexture,
338 emissiveTexture: emissiveTexture,
339 )
340 var 409 var
341 header: glTFHeader 410 header: glTFHeader
342 data: glTFData 411 data: glTFData
343 412
344 for name, value in fieldPairs(header): 413 for name, value in fieldPairs(header):
365 434
366 debug "Loading mesh: ", data.structuredContent.pretty 435 debug "Loading mesh: ", data.structuredContent.pretty
367 436
368 if "materials" in data.structuredContent: 437 if "materials" in data.structuredContent:
369 for materialnode in items(data.structuredContent["materials"]): 438 for materialnode in items(data.structuredContent["materials"]):
370 result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, mapping) 439 result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, materialAttributesMapping)
371 440
372 if "textures" in data.structuredContent: 441 if "textures" in data.structuredContent:
373 for texturenode in items(data.structuredContent["textures"]): 442 for texturenode in items(data.structuredContent["textures"]):
374 result.textures.add loadTexture(data.structuredContent, texturenode, data.binaryBufferData) 443 result.textures.add loadTexture(data.structuredContent, texturenode, data.binaryBufferData)
375 444
376 echo result 445 if "meshes" in data.structuredContent:
377 # for scenedata in data.structuredContent["scenes"]: 446 for mesh in items(data.structuredContent["meshes"]):
378 # result.add data.structuredContent.loadScene(scenedata, materials, data.binaryBufferData) 447 var primitives: seq[(TMesh, VkPrimitiveTopology)]
379 # 448 for primitive in items(mesh["primitives"]):
449 primitives.add loadPrimitive[TMesh](data.structuredContent, primitive, meshAttributesMapping, data.binaryBufferData)
450 result.meshes.add primitives
451
452 echo "Textures:"
453 for t in result.textures:
454 echo " ", t
455
456 echo "Materials:"
457 for m in result.materials:
458 echo " ", m
459
460 echo "Meshes:"
461 for m in result.meshes:
462 echo " Primitives:"
463 for p in m:
464 echo " ", p[1], ": ", p[0]
465
380 proc LoadMeshes*[TMesh, TMaterial]( 466 proc LoadMeshes*[TMesh, TMaterial](
381 path: string, 467 path: string,
382 baseColorFactor: static string = "", 468 meshAttributesMapping: static MeshAttributeNames,
383 emissiveFactor: static string = "", 469 materialAttributesMapping: static MaterialAttributeNames,
384 metallicFactor: static string = "",
385 roughnessFactor: static string = "",
386 baseColorTexture: static string = "",
387 metallicRoughnessTexture: static string = "",
388 normalTexture: static string = "",
389 occlusionTexture: static string = "",
390 emissiveTexture: static string = "",
391 package = DEFAULT_PACKAGE 470 package = DEFAULT_PACKAGE
392 ): GLTFMesh[TMesh, TMaterial] = 471 ): GLTFMesh[TMesh, TMaterial] =
393 ReadglTF[TMesh, TMaterial]( 472 ReadglTF[TMesh, TMaterial](
394 stream = loadResource_intern(path, package = package), 473 stream = loadResource_intern(path, package = package),
395 baseColorFactor = baseColorFactor, 474 meshAttributesMapping = meshAttributesMapping,
396 emissiveFactor = emissiveFactor, 475 materialAttributesMapping = materialAttributesMapping,
397 metallicFactor = metallicFactor,
398 roughnessFactor = roughnessFactor,
399 baseColorTexture = baseColorTexture,
400 metallicRoughnessTexture = metallicRoughnessTexture,
401 normalTexture = normalTexture,
402 occlusionTexture = occlusionTexture,
403 emissiveTexture = emissiveTexture,
404 ) 476 )