comparison semiconginev2/gltf.nim @ 1245:d594b1d07d49

add: initial changes for glTF loader
author sam <sam@basx.dev>
date Wed, 24 Jul 2024 00:26:57 +0700
parents 7e55fde39ca8
children c15770761865
comparison
equal deleted inserted replaced
1244:3ef5764504ad 1245:d594b1d07d49
1 type 1 type
2 GLTFMesh[TMesh, TMaterial] = object
3 scenes: seq[int]
4 nodes: seq[int]
5 meshes: seq[TMesh]
6 materials: seq[TMaterial]
2 glTFHeader = object 7 glTFHeader = object
3 magic: uint32 8 magic: uint32
4 version: uint32 9 version: uint32
5 length: uint32 10 length: uint32
6 glTFData = object 11 glTFData = object
7 structuredContent: JsonNode 12 structuredContent: JsonNode
8 binaryBufferData: seq[uint8] 13 binaryBufferData: seq[uint8]
9 14
15 MaterialAttributeNames = object
16 baseColorFactor: string
17 emissiveFactor: string
18 metallicFactor: string
19 roughnessFactor: string
20 baseColorTexture: string
21 metallicRoughnessTexture: string
22 normalTexture: string
23 occlusionTexture: string
24 emissiveTexture: string
25
10 const 26 const
27 HEADER_MAGIC = 0x46546C67
11 JSON_CHUNK = 0x4E4F534A 28 JSON_CHUNK = 0x4E4F534A
12 BINARY_CHUNK = 0x004E4942 29 BINARY_CHUNK = 0x004E4942
13 ACCESSOR_TYPE_MAP = { 30 ACCESSOR_TYPE_MAP = {
14 5120: Int8, 31 5120: Int8,
15 5121: UInt8, 32 5121: UInt8,
148 result.sampler.wrapModeS = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()] 165 result.sampler.wrapModeS = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()]
149 if sampler.hasKey("wrapT"): 166 if sampler.hasKey("wrapT"):
150 result.sampler.wrapModeT = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()] 167 result.sampler.wrapModeT = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()]
151 168
152 169
153 proc loadMaterial(root: JsonNode, materialNode: JsonNode, defaultMaterial: MaterialType, mainBuffer: seq[uint8]): MaterialData = 170 proc loadMaterial[TMaterial](
171 root: JsonNode,
172 materialNode: JsonNode,
173 mainBuffer: seq[uint8],
174 mapping: MaterialAttributeNames
175 ): TMaterial =
154 let pbr = materialNode["pbrMetallicRoughness"] 176 let pbr = materialNode["pbrMetallicRoughness"]
155 var attributes: Table[string, DataList] 177 for glName, glValue in fieldPairs(mapping):
178 if glValue != "":
179 for name, value in fieldPairs(result):
180 when name == glName:
181 value =
182
183 #[
156 184
157 # color 185 # color
158 if defaultMaterial.attributes.contains("color"): 186 if defaultMaterial.attributes.contains("color"):
159 attributes["color"] = InitDataList(thetype = Vec4F32) 187 attributes["color"] = InitDataList(thetype = Vec4F32)
160 if pbr.hasKey(GLTF_MATERIAL_MAPPING["color"]): 188 if pbr.hasKey(GLTF_MATERIAL_MAPPING["color"]):
205 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][1].getFloat(), 233 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][1].getFloat(),
206 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][2].getFloat(), 234 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][2].getFloat(),
207 )] 235 )]
208 else: 236 else:
209 attributes["emissiveColor"] = @[NewVec3f(1'f32, 1'f32, 1'f32)] 237 attributes["emissiveColor"] = @[NewVec3f(1'f32, 1'f32, 1'f32)]
210 238 ]#
211 result = InitMaterialData(theType = defaultMaterial, name = materialNode["name"].getStr(), attributes = attributes) 239
212 240
213 proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = 241 proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh =
214 if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: 242 if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4:
215 raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode") 243 raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode")
216 244
311 # children 339 # children
312 if node.hasKey("children"): 340 if node.hasKey("children"):
313 for childNode in node["children"]: 341 for childNode in node["children"]:
314 result.children.add loadNode(root, root["nodes"][childNode.getInt()], materials, mainBuffer) 342 result.children.add loadNode(root, root["nodes"][childNode.getInt()], materials, mainBuffer)
315 343
316 proc loadMeshTree(root: JsonNode, scenenode: JsonNode, materials: seq[MaterialData], mainBuffer: var seq[uint8]): MeshTree = 344 proc loadScene(root: JsonNode, scenenode: JsonNode, materials: seq[MaterialData], mainBuffer: var seq[uint8]): MeshTree =
317 result = MeshTree() 345 result = MeshTree()
318 for nodeId in scenenode["nodes"]: 346 for nodeId in scenenode["nodes"]:
319 result.children.add loadNode(root, root["nodes"][nodeId.getInt()], materials, mainBuffer) 347 result.children.add loadNode(root, root["nodes"][nodeId.getInt()], materials, mainBuffer)
320 # TODO: getting from gltf to vulkan system is still messed up somehow (i.e. not consistent for different files), see other TODO 348 # TODO: getting from gltf to vulkan system is still messed up somehow (i.e. not consistent for different files), see other TODO
321 # result.transform = Scale(1, -1, 1) 349 # result.transform = Scale(1, -1, 1)
322 result.updateTransforms() 350 result.updateTransforms()
323 351
324 352
325 proc ReadglTF*(stream: Stream, defaultMaterial: MaterialType): seq[MeshTree] = 353 proc ReadglTF*[TMaterial, TMesh](
354 stream: Stream,
355 attributeNames: MaterialAttributeNames,
356 baseColorFactor = "",
357 emissiveFactor = "",
358 metallicFactor = "",
359 roughnessFactor = "",
360 baseColorTexture = "",
361 metallicRoughnessTexture = "",
362 normalTexture = "",
363 occlusionTexture = "",
364 emissiveTexture = "",
365 ): GLTFMesh[TMesh, TMaterial] =
366 let mapping = MaterialAttributeNames(
367 baseColorFactor: baseColorFactor
368 emissiveFactor: emissiveFactor
369 metallicFactor: metallicFactor
370 roughnessFactor: roughnessFactor
371 baseColorTexture: baseColorTexture
372 metallicRoughnessTexture: metallicRoughnessTexture
373 normalTexture: normalTexture
374 occlusionTexture: occlusionTexture
375 emissiveTexture: emissiveTexture
376 )
326 var 377 var
327 header: glTFHeader 378 header: glTFHeader
328 data: glTFData 379 data: glTFData
329 380
330 for name, value in fieldPairs(header): 381 for name, value in fieldPairs(header):
331 stream.read(value) 382 stream.read(value)
332 383
333 assert header.magic == 0x46546C67 384 assert header.magic == HEADER_MAGIC
334 assert header.version == 2 385 assert header.version == 2
335 386
336 var chunkLength = stream.readUint32() 387 var chunkLength = stream.readUint32()
337 assert stream.readUint32() == JSON_CHUNK 388 assert stream.readUint32() == JSON_CHUNK
338 data.structuredContent = parseJson(stream.readStr(int(chunkLength))) 389 data.structuredContent = parseJson(stream.readStr(int(chunkLength)))
351 402
352 debug "Loading mesh: ", data.structuredContent.pretty 403 debug "Loading mesh: ", data.structuredContent.pretty
353 404
354 var materials: seq[MaterialData] 405 var materials: seq[MaterialData]
355 for materialnode in data.structuredContent["materials"]: 406 for materialnode in data.structuredContent["materials"]:
356 materials.add data.structuredContent.loadMaterial(materialnode, defaultMaterial, data.binaryBufferData) 407 result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, mapping)
357 408
358 for scenedata in data.structuredContent["scenes"]: 409 for scenedata in data.structuredContent["scenes"]:
359 result.add data.structuredContent.loadMeshTree(scenedata, materials, data.binaryBufferData) 410 result.add data.structuredContent.loadScene(scenedata, materials, data.binaryBufferData)