Mercurial > games > semicongine
changeset 1250:9ceb509af5ea
add: loading of most kinds of data from gltf
author | sam <sam@basx.dev> |
---|---|
date | Thu, 25 Jul 2024 23:15:05 +0700 |
parents | d83726af7abb |
children | 3f98ad20a9d3 |
files | semiconginev2/gltf.nim |
diffstat | 1 files changed, 51 insertions(+), 251 deletions(-) [+] |
line wrap: on
line diff
--- a/semiconginev2/gltf.nim Thu Jul 25 22:41:24 2024 +0700 +++ b/semiconginev2/gltf.nim Thu Jul 25 23:15:05 2024 +0700 @@ -1,7 +1,11 @@ type - GLTFMesh*[TMesh, TMaterial] = object + GltfNode* = object + children: seq[int] + mesh: int + transform: Mat4 + GltfMesh*[TMesh, TMaterial] = object scenes*: seq[seq[int]] # each scene has a seq of node indices - nodes*: seq[seq[int]] # each node has a seq of mesh indices + nodes*: seq[GltfNode] # each node has a seq of mesh indices meshes*: seq[seq[(TMesh, VkPrimitiveTopology)]] materials*: seq[TMaterial] textures*: seq[Image[BGRA]] @@ -43,32 +47,10 @@ indices*: string material*: string -#[ -static: - let TypeIds = { - int8: 5120, - uint8: 5121, - int16: 5122, - uint16: 5123, - uint32: 5125, - float32: 5126, - }.toTable -]# - const HEADER_MAGIC = 0x46546C67 JSON_CHUNK = 0x4E4F534A BINARY_CHUNK = 0x004E4942 - #[ - ACCESSOR_TYPE_MAP = { - 5120: Int8, - 5121: UInt8, - 5122: Int16, - 5123: UInt16, - 5125: UInt32, - 5126: Float32, - }.toTable - ]# SAMPLER_FILTER_MODE_MAP = { 9728: VK_FILTER_NEAREST, 9729: VK_FILTER_LINEAR, @@ -92,44 +74,6 @@ 6: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, ] -#[ -proc getGPUType(accessor: JsonNode, attribute: string): DataType = - # TODO: no full support for all datatypes that glTF may provide - # semicongine/core/gpu_data should maybe generated with macros to allow for all combinations - let componentType = ACCESSOR_TYPE_MAP[accessor["componentType"].getInt()] - let theType = accessor["type"].getStr() - case theType - of "SCALAR": - return componentType - of "VEC2": - case componentType - of UInt32: return Vec2U32 - of Float32: return Vec2F32 - else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") - of "VEC3": - case componentType - of UInt32: return Vec3U32 - of Float32: return Vec3F32 - else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") - of "VEC4": - case componentType - of UInt32: return Vec4U32 - of Float32: return Vec4F32 - else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") - of "MAT2": - case componentType - of Float32: return Vec4F32 - else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") - of "MAT3": - case componentType - of Float32: return Vec4F32 - else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") - of "MAT4": - case componentType - of Float32: return Vec4F32 - else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") -]# - proc getBufferViewData(bufferView: JsonNode, mainBuffer: seq[uint8], baseBufferOffset = 0): seq[uint8] = assert bufferView["buffer"].getInt() == 0, "Currently no external buffers supported" @@ -278,188 +222,48 @@ let accessor = primitive["attributes"][gltfAttributeIndexed].getInt() resultValue.data = getAccessorData[elementType(resultValue.data)](root, root["accessors"][accessor], mainBuffer) inc i - #[ - when gltfAttribute == "indices": - if primitive.hasKey(gltfAttribute): - let accessor = primitive[gltfAttribute].getInt() - value.data = getAccessorData[elementType(value.data)](root, root["accessors"][accessor], mainBuffer) - elif gltfAttribute == "material": - if primitive.hasKey(gltfAttribute): - value.data = typeof(value.data)(primitive[gltfAttribute].getInt()) - else: - if primitive["attributes"].hasKey(gltfAttribute): - let accessor = primitive["attributes"][gltfAttribute].getInt() - value.data = getAccessorData[elementType(value.data)](root, root["accessors"][accessor], mainBuffer) - ]# - #[ - var indexType = None - let indexed = primitive.hasKey("indices") - if indexed: - var indexCount = root["accessors"][primitive["indices"].getInt()]["count"].getInt() - if indexCount < int(high(uint16)): - indexType = Small - else: - indexType = Big - - for attribute, accessor in primitive["attributes"].pairs: - let data = root.getAccessorData(root["accessors"][accessor.getInt()], mainBuffer) - if result.vertexCount == 0: - result.vertexCount = data.len - assert data.len == result.vertexCount - result[].InitVertexAttribute(attribute.toLowerAscii, data) - - if primitive.hasKey("material"): - let materialId = primitive["material"].getInt() - result[].material = materials[materialId] - else: - result[].material = EMPTY_MATERIAL.InitMaterialData() - - if primitive.hasKey("indices"): - assert result[].indexType != None - let data = root.getAccessorData(root["accessors"][primitive["indices"].getInt()], mainBuffer) - var tri: seq[int] - case data.thetype - of UInt16: - for entry in data[uint16][]: - tri.add int(entry) - if tri.len == 3: - # FYI gltf uses counter-clockwise indexing - result[].AppendIndicesData(tri[0], tri[1], tri[2]) - tri.setLen(0) - of UInt32: - for entry in data[uint32][]: - tri.add int(entry) - if tri.len == 3: - # FYI gltf uses counter-clockwise indexing - result[].AppendIndicesData(tri[0], tri[1], tri[2]) - tri.setLen(0) - else: - raise newException(Exception, &"Unsupported index data type: {data.thetype}") - ]# - - -#[ - -proc loadPrimitive(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = - if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: - raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode") - - var indexType = None - let indexed = primitiveNode.hasKey("indices") - if indexed: - # TODO: Tiny indices - var indexCount = root["accessors"][primitiveNode["indices"].getInt()]["count"].getInt() - if indexCount < int(high(uint16)): - indexType = Small - else: - indexType = Big - - result = Mesh( - instanceTransforms: @[Unit4F32], - indexType: indexType, - name: meshname, - vertexCount: 0, - ) +proc loadNode(node: JsonNode): GltfNode = + result.transform = Unit4 + if "mesh" in node: + result.mesh = node["mesh"].getInt() + if "children" in node: + for child in items(node["children"]): + result.children.add child.getInt() + if "matrix" in node: + for i in 0 ..< node["matrix"].len: + result.transform[i] = node["matrix"][i].getFloat() - for attribute, accessor in primitiveNode["attributes"].pairs: - let data = root.getAccessorData(root["accessors"][accessor.getInt()], mainBuffer) - if result.vertexCount == 0: - result.vertexCount = data.len - assert data.len == result.vertexCount - result[].InitVertexAttribute(attribute.toLowerAscii, data) - - if primitiveNode.hasKey("material"): - let materialId = primitiveNode["material"].getInt() - result[].material = materials[materialId] - else: - result[].material = EMPTY_MATERIAL.InitMaterialData() - - if primitiveNode.hasKey("indices"): - assert result[].indexType != None - let data = root.getAccessorData(root["accessors"][primitiveNode["indices"].getInt()], mainBuffer) - var tri: seq[int] - case data.thetype - of UInt16: - for entry in data[uint16][]: - tri.add int(entry) - if tri.len == 3: - # FYI gltf uses counter-clockwise indexing - result[].AppendIndicesData(tri[0], tri[1], tri[2]) - tri.setLen(0) - of UInt32: - for entry in data[uint32][]: - tri.add int(entry) - if tri.len == 3: - # FYI gltf uses counter-clockwise indexing - result[].AppendIndicesData(tri[0], tri[1], tri[2]) - tri.setLen(0) - else: - raise newException(Exception, &"Unsupported index data type: {data.thetype}") - # TODO: getting from gltf to vulkan system is still messed up somehow, see other TODO - Transform[Vec3f](result[], "position", Scale(1, -1, 1)) - - -proc loadNode(root: JsonNode, node: JsonNode, materials: seq[MaterialData], mainBuffer: var seq[uint8]): MeshTree = - result = MeshTree() - # mesh - if node.hasKey("mesh"): - let mesh = root["meshes"][node["mesh"].getInt()] - for primitive in mesh["primitives"]: - result.children.add MeshTree(mesh: loadPrimitive(mesh["name"].getStr(), root, primitive, materials, mainBuffer)) + var (t, r, s) = (Unit4, Unit4, Unit4) + if "translation" in node: + t = Translate( + float32(node["translation"][0].getFloat()), + float32(node["translation"][1].getFloat()), + float32(node["translation"][2].getFloat()) + ) + if "rotation" in node: + t = Rotate( + float32(node["rotation"][3].getFloat()), + NewVec3f( + float32(node["rotation"][0].getFloat()), + float32(node["rotation"][1].getFloat()), + float32(node["rotation"][2].getFloat()) + ) + ) + if "scale" in node: + t = Scale( + float32(node["scale"][0].getFloat()), + float32(node["scale"][1].getFloat()), + float32(node["scale"][2].getFloat()) + ) - # transformation - if node.hasKey("matrix"): - var mat: Mat4 - for i in 0 ..< node["matrix"].len: - mat[i] = node["matrix"][i].getFloat() - result.transform = mat - else: - var (t, r, s) = (Unit4F32, Unit4F32, Unit4F32) - if node.hasKey("translation"): - t = Translate( - float32(node["translation"][0].getFloat()), - float32(node["translation"][1].getFloat()), - float32(node["translation"][2].getFloat()) - ) - if node.hasKey("rotation"): - t = Rotate( - float32(node["rotation"][3].getFloat()), - NewVec3f( - float32(node["rotation"][0].getFloat()), - float32(node["rotation"][1].getFloat()), - float32(node["rotation"][2].getFloat()) - ) - ) - if node.hasKey("scale"): - t = Scale( - float32(node["scale"][0].getFloat()), - float32(node["scale"][1].getFloat()), - float32(node["scale"][2].getFloat()) - ) - result.transform = t * r * s - result.transform = Scale(1, -1, 1) * result.transform - - # children - if node.hasKey("children"): - for childNode in node["children"]: - result.children.add loadNode(root, root["nodes"][childNode.getInt()], materials, mainBuffer) - -proc loadScene(root: JsonNode, scenenode: JsonNode, materials: seq[MaterialData], mainBuffer: var seq[uint8]): MeshTree = - result = MeshTree() - for nodeId in scenenode["nodes"]: - result.children.add loadNode(root, root["nodes"][nodeId.getInt()], materials, mainBuffer) - # TODO: getting from gltf to vulkan system is still messed up somehow (i.e. not consistent for different files), see other TODO - # result.transform = Scale(1, -1, 1) - result.updateTransforms() - - ]# + result.transform = t * r * s * result.transform proc ReadglTF*[TMesh, TMaterial]( stream: Stream, meshAttributesMapping: static MeshAttributeNames, materialAttributesMapping: static MaterialAttributeNames, -): GLTFMesh[TMesh, TMaterial] = +): GltfMesh[TMesh, TMaterial] = var header: glTFHeader data: glTFData @@ -503,28 +307,24 @@ primitives.add loadPrimitive[TMesh](data.structuredContent, primitive, meshAttributesMapping, data.binaryBufferData) result.meshes.add primitives - echo "Textures:" - for t in result.textures: - echo " ", t - - echo "Materials:" - for m in result.materials: - echo " ", m + if "nodes" in data.structuredContent: + for node in items(data.structuredContent["nodes"]): + result.nodes.add loadNode(node) - echo "Meshes:" - for m in result.meshes: - echo " Primitives:" - for p in m: - for field, value in fieldPairs(p[0]): - if typeof(value) is GPUData: - echo " ", field, ": ", value.data.len + if "scenes" in data.structuredContent: + for scene in items(data.structuredContent["scenes"]): + if "nodes" in scene: + var nodes: seq[int] + for nodeId in items(scene["nodes"]): + nodes.add nodeId.getInt() + result.scenes.add nodes proc LoadMeshes*[TMesh, TMaterial]( path: string, meshAttributesMapping: static MeshAttributeNames, materialAttributesMapping: static MaterialAttributeNames, package = DEFAULT_PACKAGE -): GLTFMesh[TMesh, TMaterial] = +): GltfMesh[TMesh, TMaterial] = ReadglTF[TMesh, TMaterial]( stream = loadResource_intern(path, package = package), meshAttributesMapping = meshAttributesMapping,