Mercurial > games > semicongine
comparison semiconginev2/gltf.nim @ 1247:c15770761865
add: gltf loading test, gltf loading for materials
author | sam <sam@basx.dev> |
---|---|
date | Wed, 24 Jul 2024 23:26:34 +0700 |
parents | d594b1d07d49 |
children | 317bb5a73606 |
comparison
equal
deleted
inserted
replaced
1246:356089365076 | 1247:c15770761865 |
---|---|
1 type | 1 type |
2 GLTFMesh[TMesh, TMaterial] = object | 2 GLTFMesh*[TMesh, TMaterial] = object |
3 scenes: seq[int] | 3 scenes*: seq[seq[int]] # each scene has a seq of node indices |
4 nodes: seq[int] | 4 nodes*: seq[seq[int]] # each node has a seq of mesh indices |
5 meshes: seq[TMesh] | 5 meshes*: seq[TMesh] |
6 materials: seq[TMaterial] | 6 materials*: seq[TMaterial] |
7 textures*: seq[Image[BGRA]] | |
7 glTFHeader = object | 8 glTFHeader = object |
8 magic: uint32 | 9 magic: uint32 |
9 version: uint32 | 10 version: uint32 |
10 length: uint32 | 11 length: uint32 |
11 glTFData = object | 12 glTFData = object |
12 structuredContent: JsonNode | 13 structuredContent: JsonNode |
13 binaryBufferData: seq[uint8] | 14 binaryBufferData: seq[uint8] |
14 | 15 |
15 MaterialAttributeNames = object | 16 MaterialAttributeNames = object |
17 # pbr | |
18 baseColorTexture: string | |
19 baseColorTextureUv: string | |
16 baseColorFactor: string | 20 baseColorFactor: string |
17 emissiveFactor: string | 21 metallicRoughnessTexture: string |
22 metallicRoughnessTextureUv: string | |
18 metallicFactor: string | 23 metallicFactor: string |
19 roughnessFactor: string | 24 roughnessFactor: string |
20 baseColorTexture: string | 25 |
21 metallicRoughnessTexture: string | 26 # other |
22 normalTexture: string | 27 normalTexture: string |
28 normalTextureUv: string | |
23 occlusionTexture: string | 29 occlusionTexture: string |
30 occlusionTextureUv: string | |
24 emissiveTexture: string | 31 emissiveTexture: string |
32 emissiveTextureUv: string | |
33 emissiveFactor: string | |
34 | |
35 #[ | |
36 static: | |
37 let TypeIds = { | |
38 int8: 5120, | |
39 uint8: 5121, | |
40 int16: 5122, | |
41 uint16: 5123, | |
42 uint32: 5125, | |
43 float32: 5126, | |
44 }.toTable | |
45 ]# | |
25 | 46 |
26 const | 47 const |
27 HEADER_MAGIC = 0x46546C67 | 48 HEADER_MAGIC = 0x46546C67 |
28 JSON_CHUNK = 0x4E4F534A | 49 JSON_CHUNK = 0x4E4F534A |
29 BINARY_CHUNK = 0x004E4942 | 50 BINARY_CHUNK = 0x004E4942 |
51 #[ | |
30 ACCESSOR_TYPE_MAP = { | 52 ACCESSOR_TYPE_MAP = { |
31 5120: Int8, | 53 5120: Int8, |
32 5121: UInt8, | 54 5121: UInt8, |
33 5122: Int16, | 55 5122: Int16, |
34 5123: UInt16, | 56 5123: UInt16, |
35 5125: UInt32, | 57 5125: UInt32, |
36 5126: Float32, | 58 5126: Float32, |
37 }.toTable | 59 }.toTable |
60 ]# | |
38 SAMPLER_FILTER_MODE_MAP = { | 61 SAMPLER_FILTER_MODE_MAP = { |
39 9728: VK_FILTER_NEAREST, | 62 9728: VK_FILTER_NEAREST, |
40 9729: VK_FILTER_LINEAR, | 63 9729: VK_FILTER_LINEAR, |
41 9984: VK_FILTER_NEAREST, | 64 9984: VK_FILTER_NEAREST, |
42 9985: VK_FILTER_LINEAR, | 65 9985: VK_FILTER_LINEAR, |
46 SAMPLER_WRAP_MODE_MAP = { | 69 SAMPLER_WRAP_MODE_MAP = { |
47 33071: VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | 70 33071: VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
48 33648: VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, | 71 33648: VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, |
49 10497: VK_SAMPLER_ADDRESS_MODE_REPEAT | 72 10497: VK_SAMPLER_ADDRESS_MODE_REPEAT |
50 }.toTable | 73 }.toTable |
51 GLTF_MATERIAL_MAPPING = { | 74 |
52 "color": "baseColorFactor", | 75 #[ |
53 "emissiveColor": "emissiveFactor", | |
54 "metallic": "metallicFactor", | |
55 "roughness", "roughnessFactor", | |
56 "baseTexture": "baseColorTexture", | |
57 "metallicRoughnessTexture": "metallicRoughnessTexture", | |
58 "normalTexture": "normalTexture", | |
59 "occlusionTexture": "occlusionTexture", | |
60 "emissiveTexture": "emissiveTexture", | |
61 }.toTable | |
62 | |
63 proc getGPUType(accessor: JsonNode, attribute: string): DataType = | 76 proc getGPUType(accessor: JsonNode, attribute: string): DataType = |
64 # TODO: no full support for all datatypes that glTF may provide | 77 # TODO: no full support for all datatypes that glTF may provide |
65 # semicongine/core/gpu_data should maybe generated with macros to allow for all combinations | 78 # semicongine/core/gpu_data should maybe generated with macros to allow for all combinations |
66 let componentType = ACCESSOR_TYPE_MAP[accessor["componentType"].getInt()] | 79 let componentType = ACCESSOR_TYPE_MAP[accessor["componentType"].getInt()] |
67 let theType = accessor["type"].getStr() | 80 let theType = accessor["type"].getStr() |
93 else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") | 106 else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") |
94 of "MAT4": | 107 of "MAT4": |
95 case componentType | 108 case componentType |
96 of Float32: return Vec4F32 | 109 of Float32: return Vec4F32 |
97 else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") | 110 else: raise newException(Exception, &"Unsupported data type for attribute '{attribute}': {componentType} {theType}") |
111 ]# | |
98 | 112 |
99 proc getBufferViewData(bufferView: JsonNode, mainBuffer: seq[uint8], baseBufferOffset = 0): seq[uint8] = | 113 proc getBufferViewData(bufferView: JsonNode, mainBuffer: seq[uint8], baseBufferOffset = 0): seq[uint8] = |
100 assert bufferView["buffer"].getInt() == 0, "Currently no external buffers supported" | 114 assert bufferView["buffer"].getInt() == 0, "Currently no external buffers supported" |
101 | 115 |
102 result = newSeq[uint8](bufferView["byteLength"].getInt()) | 116 result = newSeq[uint8](bufferView["byteLength"].getInt()) |
105 | 119 |
106 if bufferView.hasKey("byteStride"): | 120 if bufferView.hasKey("byteStride"): |
107 raise newException(Exception, "Unsupported feature: byteStride in buffer view") | 121 raise newException(Exception, "Unsupported feature: byteStride in buffer view") |
108 copyMem(dstPointer, addr mainBuffer[bufferOffset], result.len) | 122 copyMem(dstPointer, addr mainBuffer[bufferOffset], result.len) |
109 | 123 |
124 #[ | |
110 proc getAccessorData(root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): DataList = | 125 proc getAccessorData(root: JsonNode, accessor: JsonNode, mainBuffer: seq[uint8]): DataList = |
111 result = InitDataList(thetype = accessor.getGPUType("??")) | 126 result = InitDataList(thetype = accessor.getGPUType("??")) |
112 result.SetLen(accessor["count"].getInt()) | 127 result.SetLen(accessor["count"].getInt()) |
113 | 128 |
114 let bufferView = root["bufferViews"][accessor["bufferView"].getInt()] | 129 let bufferView = root["bufferViews"][accessor["bufferView"].getInt()] |
128 for i in 0 ..< int(result.len): | 143 for i in 0 ..< int(result.len): |
129 copyMem(dstPointer, addr mainBuffer[bufferOffset + i * bufferView["byteStride"].getInt()], int(result.thetype.Size)) | 144 copyMem(dstPointer, addr mainBuffer[bufferOffset + i * bufferView["byteStride"].getInt()], int(result.thetype.Size)) |
130 dstPointer = cast[pointer](cast[uint](dstPointer) + result.thetype.Size) | 145 dstPointer = cast[pointer](cast[uint](dstPointer) + result.thetype.Size) |
131 else: | 146 else: |
132 copyMem(dstPointer, addr mainBuffer[bufferOffset], length) | 147 copyMem(dstPointer, addr mainBuffer[bufferOffset], length) |
133 | 148 ]# |
134 proc loadImage(root: JsonNode, imageIndex: int, mainBuffer: seq[uint8]): Image[RGBAPixel] = | 149 |
150 proc loadTexture(root: JsonNode, textureNode: JsonNode, mainBuffer: seq[uint8]): Image[BGRA] = | |
151 | |
152 let imageIndex = textureNode["source"].getInt() | |
153 | |
135 if root["images"][imageIndex].hasKey("uri"): | 154 if root["images"][imageIndex].hasKey("uri"): |
136 raise newException(Exception, "Unsupported feature: Load images from external files") | 155 raise newException(Exception, "Unsupported feature: Cannot load images from external files") |
156 let imageType = root["images"][imageIndex]["mimeType"].getStr() | |
157 assert imageType == "image/png", "glTF loader currently only supports PNG" | |
137 | 158 |
138 let bufferView = root["bufferViews"][root["images"][imageIndex]["bufferView"].getInt()] | 159 let bufferView = root["bufferViews"][root["images"][imageIndex]["bufferView"].getInt()] |
139 let imgData = newStringStream(cast[string](getBufferViewData(bufferView, mainBuffer))) | 160 result = LoadImage[BGRA](getBufferViewData(bufferView, mainBuffer)) |
140 | |
141 let imageType = root["images"][imageIndex]["mimeType"].getStr() | |
142 case imageType | |
143 of "image/bmp": | |
144 result = ReadBMP(imgData) | |
145 of "image/png": | |
146 result = ReadPNG(imgData) | |
147 else: | |
148 raise newException(Exception, "Unsupported feature: Load image of type " & imageType) | |
149 | |
150 proc loadTexture(root: JsonNode, textureIndex: int, mainBuffer: seq[uint8]): Texture = | |
151 let textureNode = root["textures"][textureIndex] | |
152 result = Texture(isGrayscale: false) | |
153 result.colorImage = loadImage(root, textureNode["source"].getInt(), mainBuffer) | |
154 result.name = root["images"][textureNode["source"].getInt()]["name"].getStr() | |
155 if result.name == "": | |
156 result.name = &"Texture{textureIndex}" | |
157 | 161 |
158 if textureNode.hasKey("sampler"): | 162 if textureNode.hasKey("sampler"): |
159 let sampler = root["samplers"][textureNode["sampler"].getInt()] | 163 let sampler = root["samplers"][textureNode["sampler"].getInt()] |
160 if sampler.hasKey("magFilter"): | 164 if sampler.hasKey("magFilter"): |
161 result.sampler.magnification = SAMPLER_FILTER_MODE_MAP[sampler["magFilter"].getInt()] | 165 result.magInterpolation = SAMPLER_FILTER_MODE_MAP[sampler["magFilter"].getInt()] |
162 if sampler.hasKey("minFilter"): | 166 if sampler.hasKey("minFilter"): |
163 result.sampler.minification = SAMPLER_FILTER_MODE_MAP[sampler["minFilter"].getInt()] | 167 result.minInterpolation = SAMPLER_FILTER_MODE_MAP[sampler["minFilter"].getInt()] |
164 if sampler.hasKey("wrapS"): | 168 if sampler.hasKey("wrapS"): |
165 result.sampler.wrapModeS = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()] | 169 result.wrapU = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()] |
166 if sampler.hasKey("wrapT"): | 170 if sampler.hasKey("wrapT"): |
167 result.sampler.wrapModeT = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()] | 171 result.wrapV = SAMPLER_WRAP_MODE_MAP[sampler["wrapT"].getInt()] |
168 | 172 |
173 proc getVec4f(node: JsonNode): Vec4f = | |
174 NewVec4f(node[0].getFloat(), node[1].getFloat(), node[2].getFloat(), node[3].getFloat()) | |
169 | 175 |
170 proc loadMaterial[TMaterial]( | 176 proc loadMaterial[TMaterial]( |
171 root: JsonNode, | 177 root: JsonNode, |
172 materialNode: JsonNode, | 178 materialNode: JsonNode, |
173 mainBuffer: seq[uint8], | 179 mainBuffer: seq[uint8], |
174 mapping: MaterialAttributeNames | 180 mapping: static MaterialAttributeNames |
175 ): TMaterial = | 181 ): TMaterial = |
182 result = TMaterial() | |
183 | |
176 let pbr = materialNode["pbrMetallicRoughness"] | 184 let pbr = materialNode["pbrMetallicRoughness"] |
177 for glName, glValue in fieldPairs(mapping): | 185 for name, value in fieldPairs(result): |
178 if glValue != "": | 186 for gltfAttribute, mappedName in fieldPairs(mapping): |
179 for name, value in fieldPairs(result): | 187 when gltfAttribute != "" and name == mappedName: |
180 when name == glName: | 188 if pbr.hasKey(gltfAttribute): |
181 value = | 189 when gltfAttribute.endsWith("Texture"): |
182 | 190 value = typeof(value)(pbr[gltfAttribute]["index"].getInt()) |
183 #[ | 191 elif gltfAttribute.endsWith("TextureUv"): |
184 | 192 value = typeof(pbr[gltfAttribute[0 ..< ^2]]["index"].getInt()) |
185 # color | 193 elif gltfAttribute in ["baseColorFactor", "emissiveFactor"]: |
186 if defaultMaterial.attributes.contains("color"): | 194 value = pbr[gltfAttribute].getVec4f() |
187 attributes["color"] = InitDataList(thetype = Vec4F32) | 195 elif gltfAttribute in ["metallicFactor", "roughnessFactor"]: |
188 if pbr.hasKey(GLTF_MATERIAL_MAPPING["color"]): | 196 value = pbr[gltfAttribute].getFloat() |
189 attributes["color"] = @[NewVec4f( | 197 else: |
190 pbr[GLTF_MATERIAL_MAPPING["color"]][0].getFloat(), | 198 {.error: "Unsupported gltf material attribute".} |
191 pbr[GLTF_MATERIAL_MAPPING["color"]][1].getFloat(), | 199 |
192 pbr[GLTF_MATERIAL_MAPPING["color"]][2].getFloat(), | 200 |
193 pbr[GLTF_MATERIAL_MAPPING["color"]][3].getFloat(), | 201 #[ |
194 )] | |
195 else: | |
196 attributes["color"] = @[NewVec4f(1, 1, 1, 1)] | |
197 | |
198 # pbr material values | |
199 for factor in ["metallic", "roughness"]: | |
200 if defaultMaterial.attributes.contains(factor): | |
201 attributes[factor] = InitDataList(thetype = Float32) | |
202 if pbr.hasKey(GLTF_MATERIAL_MAPPING[factor]): | |
203 attributes[factor] = @[float32(pbr[GLTF_MATERIAL_MAPPING[factor]].getFloat())] | |
204 else: | |
205 attributes[factor] = @[0.5'f32] | |
206 | |
207 # pbr material textures | |
208 for texture in ["baseTexture", "metallicRoughnessTexture"]: | |
209 if defaultMaterial.attributes.contains(texture): | |
210 attributes[texture] = InitDataList(thetype = TextureType) | |
211 # attributes[texture & "Index"] = InitDataList(thetype=UInt8) | |
212 if pbr.hasKey(GLTF_MATERIAL_MAPPING[texture]): | |
213 attributes[texture] = @[loadTexture(root, pbr[GLTF_MATERIAL_MAPPING[texture]]["index"].getInt(), mainBuffer)] | |
214 else: | |
215 attributes[texture] = @[EMPTY_TEXTURE] | |
216 | |
217 # generic material textures | |
218 for texture in ["normalTexture", "occlusionTexture", "emissiveTexture"]: | |
219 if defaultMaterial.attributes.contains(texture): | |
220 attributes[texture] = InitDataList(thetype = TextureType) | |
221 # attributes[texture & "Index"] = InitDataList(thetype=UInt8) | |
222 if materialNode.hasKey(GLTF_MATERIAL_MAPPING[texture]): | |
223 attributes[texture] = @[loadTexture(root, materialNode[texture]["index"].getInt(), mainBuffer)] | |
224 else: | |
225 attributes[texture] = @[EMPTY_TEXTURE] | |
226 | |
227 # emissiv color | |
228 if defaultMaterial.attributes.contains("emissiveColor"): | |
229 attributes["emissiveColor"] = InitDataList(thetype = Vec3F32) | |
230 if materialNode.hasKey(GLTF_MATERIAL_MAPPING["emissiveColor"]): | |
231 attributes["emissiveColor"] = @[NewVec3f( | |
232 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][0].getFloat(), | |
233 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][1].getFloat(), | |
234 materialNode[GLTF_MATERIAL_MAPPING["emissiveColor"]][2].getFloat(), | |
235 )] | |
236 else: | |
237 attributes["emissiveColor"] = @[NewVec3f(1'f32, 1'f32, 1'f32)] | |
238 ]# | |
239 | |
240 | 202 |
241 proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = | 203 proc loadMesh(meshname: string, root: JsonNode, primitiveNode: JsonNode, materials: seq[MaterialData], mainBuffer: seq[uint8]): Mesh = |
242 if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: | 204 if primitiveNode.hasKey("mode") and primitiveNode["mode"].getInt() != 4: |
243 raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode") | 205 raise newException(Exception, "Currently only TRIANGLE mode is supported for geometry mode") |
244 | 206 |
293 tri.setLen(0) | 255 tri.setLen(0) |
294 else: | 256 else: |
295 raise newException(Exception, &"Unsupported index data type: {data.thetype}") | 257 raise newException(Exception, &"Unsupported index data type: {data.thetype}") |
296 # TODO: getting from gltf to vulkan system is still messed up somehow, see other TODO | 258 # TODO: getting from gltf to vulkan system is still messed up somehow, see other TODO |
297 Transform[Vec3f](result[], "position", Scale(1, -1, 1)) | 259 Transform[Vec3f](result[], "position", Scale(1, -1, 1)) |
260 | |
298 | 261 |
299 proc loadNode(root: JsonNode, node: JsonNode, materials: seq[MaterialData], mainBuffer: var seq[uint8]): MeshTree = | 262 proc loadNode(root: JsonNode, node: JsonNode, materials: seq[MaterialData], mainBuffer: var seq[uint8]): MeshTree = |
300 result = MeshTree() | 263 result = MeshTree() |
301 # mesh | 264 # mesh |
302 if node.hasKey("mesh"): | 265 if node.hasKey("mesh"): |
347 result.children.add loadNode(root, root["nodes"][nodeId.getInt()], materials, mainBuffer) | 310 result.children.add loadNode(root, root["nodes"][nodeId.getInt()], materials, mainBuffer) |
348 # TODO: getting from gltf to vulkan system is still messed up somehow (i.e. not consistent for different files), see other TODO | 311 # TODO: getting from gltf to vulkan system is still messed up somehow (i.e. not consistent for different files), see other TODO |
349 # result.transform = Scale(1, -1, 1) | 312 # result.transform = Scale(1, -1, 1) |
350 result.updateTransforms() | 313 result.updateTransforms() |
351 | 314 |
352 | 315 ]# |
353 proc ReadglTF*[TMaterial, TMesh]( | 316 |
317 proc ReadglTF*[TMesh, TMaterial]( | |
354 stream: Stream, | 318 stream: Stream, |
355 attributeNames: MaterialAttributeNames, | 319 baseColorFactor: static string = "", |
356 baseColorFactor = "", | 320 emissiveFactor: static string = "", |
357 emissiveFactor = "", | 321 metallicFactor: static string = "", |
358 metallicFactor = "", | 322 roughnessFactor: static string = "", |
359 roughnessFactor = "", | 323 baseColorTexture: static string = "", |
360 baseColorTexture = "", | 324 metallicRoughnessTexture: static string = "", |
361 metallicRoughnessTexture = "", | 325 normalTexture: static string = "", |
362 normalTexture = "", | 326 occlusionTexture: static string = "", |
363 occlusionTexture = "", | 327 emissiveTexture: static string = "", |
364 emissiveTexture = "", | |
365 ): GLTFMesh[TMesh, TMaterial] = | 328 ): GLTFMesh[TMesh, TMaterial] = |
366 let mapping = MaterialAttributeNames( | 329 const mapping = MaterialAttributeNames( |
367 baseColorFactor: baseColorFactor | 330 baseColorFactor: baseColorFactor, |
368 emissiveFactor: emissiveFactor | 331 emissiveFactor: emissiveFactor, |
369 metallicFactor: metallicFactor | 332 metallicFactor: metallicFactor, |
370 roughnessFactor: roughnessFactor | 333 roughnessFactor: roughnessFactor, |
371 baseColorTexture: baseColorTexture | 334 baseColorTexture: baseColorTexture, |
372 metallicRoughnessTexture: metallicRoughnessTexture | 335 metallicRoughnessTexture: metallicRoughnessTexture, |
373 normalTexture: normalTexture | 336 normalTexture: normalTexture, |
374 occlusionTexture: occlusionTexture | 337 occlusionTexture: occlusionTexture, |
375 emissiveTexture: emissiveTexture | 338 emissiveTexture: emissiveTexture, |
376 ) | 339 ) |
377 var | 340 var |
378 header: glTFHeader | 341 header: glTFHeader |
379 data: glTFData | 342 data: glTFData |
380 | 343 |
400 let bufferLenDiff = int(chunkLength) - data.structuredContent["buffers"][0]["byteLength"].getInt() | 363 let bufferLenDiff = int(chunkLength) - data.structuredContent["buffers"][0]["byteLength"].getInt() |
401 assert 0 <= bufferLenDiff and bufferLenDiff <= 3 # binary buffer may be aligned to 4 bytes | 364 assert 0 <= bufferLenDiff and bufferLenDiff <= 3 # binary buffer may be aligned to 4 bytes |
402 | 365 |
403 debug "Loading mesh: ", data.structuredContent.pretty | 366 debug "Loading mesh: ", data.structuredContent.pretty |
404 | 367 |
405 var materials: seq[MaterialData] | 368 if "materials" in data.structuredContent: |
406 for materialnode in data.structuredContent["materials"]: | 369 for materialnode in items(data.structuredContent["materials"]): |
407 result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, mapping) | 370 result.materials.add loadMaterial[TMaterial](data.structuredContent, materialnode, data.binaryBufferData, mapping) |
408 | 371 |
409 for scenedata in data.structuredContent["scenes"]: | 372 if "textures" in data.structuredContent: |
410 result.add data.structuredContent.loadScene(scenedata, materials, data.binaryBufferData) | 373 for texturenode in items(data.structuredContent["textures"]): |
374 result.textures.add loadTexture(data.structuredContent, texturenode, data.binaryBufferData) | |
375 | |
376 echo result | |
377 # for scenedata in data.structuredContent["scenes"]: | |
378 # result.add data.structuredContent.loadScene(scenedata, materials, data.binaryBufferData) | |
379 # | |
380 proc LoadMeshes*[TMesh, TMaterial]( | |
381 path: string, | |
382 baseColorFactor: static string = "", | |
383 emissiveFactor: static string = "", | |
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 | |
392 ): GLTFMesh[TMesh, TMaterial] = | |
393 ReadglTF[TMesh, TMaterial]( | |
394 stream = loadResource_intern(path, package = package), | |
395 baseColorFactor = baseColorFactor, | |
396 emissiveFactor = emissiveFactor, | |
397 metallicFactor = metallicFactor, | |
398 roughnessFactor = roughnessFactor, | |
399 baseColorTexture = baseColorTexture, | |
400 metallicRoughnessTexture = metallicRoughnessTexture, | |
401 normalTexture = normalTexture, | |
402 occlusionTexture = occlusionTexture, | |
403 emissiveTexture = emissiveTexture, | |
404 ) |