Mercurial > games > semicongine
changeset 247:beb41c93aa3f
fix: gltf loading
author | Sam <sam@basx.dev> |
---|---|
date | Tue, 23 May 2023 01:05:06 +0700 |
parents | dcbd9f256f6a |
children | 952428f04ffc |
files | examples/E04_input.nim src/semicongine.nim src/semicongine/engine.nim src/semicongine/entity.nim src/semicongine/mesh.nim src/semicongine/renderer.nim src/semicongine/resources.nim src/semicongine/resources/mesh.nim src/semicongine/scene.nim tests/test_mesh.nim |
diffstat | 10 files changed, 243 insertions(+), 213 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/E04_input.nim Mon May 22 19:27:17 2023 +0700 +++ b/examples/E04_input.nim Tue May 23 01:05:06 2023 +0700 @@ -179,10 +179,10 @@ while myengine.updateInputs() == Running: if myengine.windowWasResized(): setShaderGlobal(scene, "projection", - ortho[float32]( - 0'f32, float32(myengine.getWindow().size[0]), - 0'f32, float32(myengine.getWindow().size[1]), - 0'f32, 1'f32, + ortho( + 0, float32(myengine.getWindow().size[0]), + 0, float32(myengine.getWindow().size[1]), + 0, 1, ) ) let
--- a/src/semicongine.nim Mon May 22 19:27:17 2023 +0700 +++ b/src/semicongine.nim Tue May 23 01:05:06 2023 +0700 @@ -3,7 +3,7 @@ import semicongine/audio import semicongine/engine -import semicongine/entity +import semicongine/scene import semicongine/events import semicongine/mesh import semicongine/renderer @@ -14,7 +14,7 @@ export audio export engine -export entity +export scene export events export mesh export renderer
--- a/src/semicongine/engine.nim Mon May 22 19:27:17 2023 +0700 +++ b/src/semicongine/engine.nim Tue May 23 01:05:06 2023 +0700 @@ -11,7 +11,7 @@ import ./vulkan/physicaldevice import ./vulkan/renderpass -import ./entity +import ./scene import ./renderer import ./events import ./audio
--- a/src/semicongine/entity.nim Mon May 22 19:27:17 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -import std/strformat -import std/tables -import std/hashes -import std/typetraits - -import ./core - -type - Component* = ref object of RootObj - entity*: Entity - - Scene* = object - name*: string - root*: Entity - shaderGlobals*: Table[string, DataList] - textures*: Table[string, seq[Texture]] - - Entity* = ref object of RootObj - name*: string - transform*: Mat4 # todo: cache transform + only update VBO when transform changed - parent*: Entity - children*: seq[Entity] - components*: seq[Component] - -func addShaderGlobal*[T](scene: var Scene, name: string, data: T) = - scene.shaderGlobals[name] = newDataList(thetype=getDataType[T]()) - setValues(scene.shaderGlobals[name], @[data]) - -func addShaderGlobalArray*[T](scene: var Scene, name: string, data: seq[T]) = - scene.shaderGlobals[name] = newDataList(thetype=getDataType[T]()) - setValues(scene.shaderGlobals[name], data) - -func getShaderGlobal*[T](scene: Scene, name: string): T = - getValues[T](scene.shaderGlobals[name])[0] - -func getShaderGlobalArray*[T](scene: Scene, name: string): seq[T] = - getValues[T](scene.shaderGlobals[name]) - -func setShaderGlobal*[T](scene: var Scene, name: string, value: T) = - setValues[T](scene.shaderGlobals[name], @[value]) - -func setShaderGlobalArray*[T](scene: var Scene, name: string, value: seq[T]) = - setValues[T](scene.shaderGlobals[name], value) - -func addTextures*(scene: var Scene, name: string, textures: seq[Texture], interpolation=VK_FILTER_LINEAR) = - scene.textures[name] = textures - -func addTexture*(scene: var Scene, name: string, texture: Texture) = - scene.textures[name] = @[texture] - -func newScene*(name: string, root: Entity): Scene = - Scene(name: name, root: root) - -func hash*(scene: Scene): Hash = - hash(scene.name) - -func `==`*(a, b: Scene): bool = - a.name == b.name - -func hash*(entity: Entity): Hash = - hash(cast[pointer](entity)) - -func hash*(component: Component): Hash = - hash(cast[pointer](component)) - -method `$`*(entity: Entity): string {.base.} = entity.name -method `$`*(component: Component): string {.base.} = - "Unknown Component" - -proc add*(entity: Entity, child: Entity) = - child.parent = entity - entity.children.add child -proc add*(entity: Entity, component: Component) = - component.entity = entity - entity.components.add component -proc add*(entity: Entity, children: seq[Entity]) = - for child in children: - child.parent = entity - entity.children.add child -proc add*(entity: Entity, components: seq[Component]) = - for component in components: - component.entity = entity - entity.components.add component - -func newEntity*(name: string = ""): Entity = - result = new Entity - result.name = name - result.transform = Unit4 - if result.name == "": - result.name = &"Entity[{$(cast[ByteAddress](result))}]" - -func newEntity*(name: string, firstChild: Entity, children: varargs[Entity]): Entity = - result = new Entity - result.add firstChild - for child in children: - result.add child - result.name = name - result.transform = Unit4 - if result.name == "": - result.name = &"Entity[{$(cast[ByteAddress](result))}]" - -proc newEntity*(name: string, firstComponent: Component, components: varargs[Component]): Entity = - result = new Entity - result.name = name - result.add firstComponent - for component in components: - result.add component - if result.name == "": - result.name = &"Entity[{$(cast[ByteAddress](result))}]" - result.transform = Unit4 - -func getModelTransform*(entity: Entity): Mat4 = - result = Unit4 - var currentEntity = entity - while currentEntity != nil: - result = currentEntity.transform * result - currentEntity = currentEntity.parent - -iterator allComponentsOfType*[T: Component](root: Entity): var T = - var queue = @[root] - while queue.len > 0: - let entity = queue.pop - for component in entity.components.mitems: - if component of T: - yield T(component) - for i in countdown(entity.children.len - 1, 0): - queue.add entity.children[i] - -func firstWithName*(root: Entity, name: string): Entity = - var queue = @[root] - while queue.len > 0: - let next = queue.pop - for child in next.children: - if child.name == name: - return child - queue.add child - -func firstComponentWithName*[T: Component](root: Entity, name: string): T = - var queue = @[root] - while queue.len > 0: - let next = queue.pop - for child in next.children: - if child.name == name: - for component in child.components: - if component of T: - return T(component) - queue.add child - -func allWithName*(root: Entity, name: string): seq[Entity] = - var queue = @[root] - while queue.len > 0: - let next = queue.pop - for child in next.children: - if child.name == name: - result.add child - queue.add child - -func allComponentsWithName*[T: Component](root: Entity, name: string): seq[T] = - var queue = @[root] - while queue.len > 0: - let next = queue.pop - for child in next.children: - if child.name == name: - for component in child.components: - if component of T: - result.add T(component) - queue.add child - -iterator allEntities*(root: Entity): Entity = - var queue = @[root] - while queue.len > 0: - let next = queue.pop - for child in next.children: - queue.add child - yield next
--- a/src/semicongine/mesh.nim Mon May 22 19:27:17 2023 +0700 +++ b/src/semicongine/mesh.nim Tue May 23 01:05:06 2023 +0700 @@ -6,7 +6,7 @@ import std/sequtils import ./core -import ./entity +import ./scene type MeshIndexType* = enum @@ -32,10 +32,9 @@ of Big: VK_INDEX_TYPE_UINT32 func vertexCount*(mesh: Mesh): uint32 = - if mesh.data.len == 0: - 0'u32 - else: - uint32(mesh.data[mesh.data.keys().toSeq[0]].len) + result = 0'u32 + for list in mesh.data.values: + result = max(list.len, result) func indicesCount*(mesh: Mesh): uint32 = (
--- a/src/semicongine/renderer.nim Mon May 22 19:27:17 2023 +0700 +++ b/src/semicongine/renderer.nim Tue May 23 01:05:06 2023 +0700 @@ -15,7 +15,7 @@ import ./vulkan/descriptor import ./vulkan/image -import ./entity +import ./scene import ./mesh type
--- a/src/semicongine/resources.nim Mon May 22 19:27:17 2023 +0700 +++ b/src/semicongine/resources.nim Tue May 23 01:05:06 2023 +0700 @@ -7,7 +7,7 @@ import ./resources/audio import ./resources/mesh -from ./entity import Entity, Scene +from ./scene import Entity, Scene export image export audio
--- a/src/semicongine/resources/mesh.nim Mon May 22 19:27:17 2023 +0700 +++ b/src/semicongine/resources/mesh.nim Tue May 23 01:05:06 2023 +0700 @@ -6,7 +6,7 @@ import std/strformat import std/streams -import ../entity +import ../scene import ../mesh import ../core @@ -201,7 +201,6 @@ result.addPrimitive(root, primitive, mainBuffer) # gld uses +y up, but we (vulkan) don't - transform[Vec3f](result, "position", scale3d(1'f32, -1'f32, 1'f32)) proc loadNode(root: JsonNode, node: JsonNode, mainBuffer: var seq[uint8]): Entity = var name = "<Unknown>" @@ -250,7 +249,9 @@ proc loadScene(root: JsonNode, scenenode: JsonNode, mainBuffer: var seq[uint8]): Scene = var rootEntity = newEntity("<root>") for nodeId in scenenode["nodes"]: - rootEntity.add loadNode(root, root["nodes"][nodeId.getInt()], mainBuffer) + let node = loadNode(root, root["nodes"][nodeId.getInt()], mainBuffer) + node.transform = node.transform * scale3d(1'f32, -1'f32, 1'f32) + rootEntity.add node newScene(scenenode["name"].getStr(), rootEntity) @@ -402,13 +403,11 @@ if emissiveFactor.len > 0: scene.addShaderGlobalArray("material_emissive_factor", emissiveFactor) # texture - #[ - if colorTexture.len > 0: scene.addShaderGlobalArray("material_color_texture", colorTexture) - if metallicRoughnessTexture.len > 0: scene.addShaderGlobalArray("material_metallic_roughness_texture", metallicRoughnessTexture) - if normalTexture.len > 0: scene.addShaderGlobalArray("material_normal_texture", normalTexture) - if occlusionTexture.len > 0: scene.addShaderGlobalArray("material_occlusion_texture", occlusionTexture) - if emissiveTexture.len > 0: scene.addShaderGlobalArray("material_emissive_texture", emissiveTexture) - ]# + if colorTexture.len > 0: scene.addTextures("material_color_texture", colorTexture) + if metallicRoughnessTexture.len > 0: scene.addTextures("material_metallic_roughness_texture", metallicRoughnessTexture) + if normalTexture.len > 0: scene.addTextures("material_normal_texture", normalTexture) + if occlusionTexture.len > 0: scene.addTextures("material_occlusion_texture", occlusionTexture) + if emissiveTexture.len > 0: scene.addTextures("material_emissive_texture", emissiveTexture) result.add scene
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/scene.nim Tue May 23 01:05:06 2023 +0700 @@ -0,0 +1,194 @@ +import std/strformat +import std/strutils +import std/tables +import std/hashes +import std/typetraits + +import ./core + +type + Component* = ref object of RootObj + entity*: Entity + + Scene* = object + name*: string + root*: Entity + shaderGlobals*: Table[string, DataList] + textures*: Table[string, seq[Texture]] + + Entity* = ref object of RootObj + name*: string + transform*: Mat4 # todo: cache transform + only update VBO when transform changed + parent*: Entity + children*: seq[Entity] + components*: seq[Component] + +func getModelTransform*(entity: Entity): Mat4 = + result = Unit4 + var currentEntity = entity + while currentEntity != nil: + result = currentEntity.transform * result + currentEntity = currentEntity.parent + +func addShaderGlobal*[T](scene: var Scene, name: string, data: T) = + scene.shaderGlobals[name] = newDataList(thetype=getDataType[T]()) + setValues(scene.shaderGlobals[name], @[data]) + +func addShaderGlobalArray*[T](scene: var Scene, name: string, data: seq[T]) = + scene.shaderGlobals[name] = newDataList(thetype=getDataType[T]()) + setValues(scene.shaderGlobals[name], data) + +func getShaderGlobal*[T](scene: Scene, name: string): T = + getValues[T](scene.shaderGlobals[name])[0] + +func getShaderGlobalArray*[T](scene: Scene, name: string): seq[T] = + getValues[T](scene.shaderGlobals[name]) + +func setShaderGlobal*[T](scene: var Scene, name: string, value: T) = + setValues[T](scene.shaderGlobals[name], @[value]) + +func setShaderGlobalArray*[T](scene: var Scene, name: string, value: seq[T]) = + setValues[T](scene.shaderGlobals[name], value) + +func addTextures*(scene: var Scene, name: string, textures: seq[Texture], interpolation=VK_FILTER_LINEAR) = + scene.textures[name] = textures + +func addTexture*(scene: var Scene, name: string, texture: Texture) = + scene.textures[name] = @[texture] + +func newScene*(name: string, root: Entity): Scene = + Scene(name: name, root: root) + +func hash*(scene: Scene): Hash = + hash(scene.name) + +func `==`*(a, b: Scene): bool = + a.name == b.name + +func hash*(entity: Entity): Hash = + hash(cast[pointer](entity)) + +func hash*(component: Component): Hash = + hash(cast[pointer](component)) + +method `$`*(entity: Entity): string {.base.} = entity.name +method `$`*(component: Component): string {.base.} = + "Unknown Component" + +proc prettyRecursive*(entity: Entity): seq[string] = + var compList: seq[string] + for comp in entity.components: + compList.add $comp + + var trans = entity.transform.col(3) + var pos = entity.getModelTransform().col(3) + result.add "- " & $entity & " [" & $trans.x & ", " & $trans.y & ", " & $trans.z & "] -> [" & $pos.x & ", " & $pos.y & ", " & $pos.z & "]" + if compList.len > 0: + result.add " [" & compList.join(", ") & "]" + + for child in entity.children: + for childLine in child.prettyRecursive: + result.add " " & childLine + +proc pretty*(entity: Entity): string = + entity.prettyRecursive.join("\n") + +proc add*(entity: Entity, child: Entity) = + child.parent = entity + entity.children.add child +proc add*(entity: Entity, component: Component) = + component.entity = entity + entity.components.add component +proc add*(entity: Entity, children: seq[Entity]) = + for child in children: + child.parent = entity + entity.children.add child +proc add*(entity: Entity, components: seq[Component]) = + for component in components: + component.entity = entity + entity.components.add component + +func newEntity*(name: string = ""): Entity = + result = new Entity + result.name = name + result.transform = Unit4 + if result.name == "": + result.name = &"Entity[{$(cast[ByteAddress](result))}]" + +func newEntity*(name: string, firstChild: Entity, children: varargs[Entity]): Entity = + result = new Entity + result.add firstChild + for child in children: + result.add child + result.name = name + result.transform = Unit4 + if result.name == "": + result.name = &"Entity[{$(cast[ByteAddress](result))}]" + +proc newEntity*(name: string, firstComponent: Component, components: varargs[Component]): Entity = + result = new Entity + result.name = name + result.add firstComponent + for component in components: + result.add component + if result.name == "": + result.name = &"Entity[{$(cast[ByteAddress](result))}]" + result.transform = Unit4 + +iterator allComponentsOfType*[T: Component](root: Entity): var T = + var queue = @[root] + while queue.len > 0: + let entity = queue.pop + for component in entity.components.mitems: + if component of T: + yield T(component) + for i in countdown(entity.children.len - 1, 0): + queue.add entity.children[i] + +func firstWithName*(root: Entity, name: string): Entity = + var queue = @[root] + while queue.len > 0: + let next = queue.pop + for child in next.children: + if child.name == name: + return child + queue.add child + +func firstComponentWithName*[T: Component](root: Entity, name: string): T = + var queue = @[root] + while queue.len > 0: + let next = queue.pop + for child in next.children: + if child.name == name: + for component in child.components: + if component of T: + return T(component) + queue.add child + +func allWithName*(root: Entity, name: string): seq[Entity] = + var queue = @[root] + while queue.len > 0: + let next = queue.pop + for child in next.children: + if child.name == name: + result.add child + queue.add child + +func allComponentsWithName*[T: Component](root: Entity, name: string): seq[T] = + var queue = @[root] + while queue.len > 0: + let next = queue.pop + for child in next.children: + if child.name == name: + for component in child.components: + if component of T: + result.add T(component) + queue.add child + +iterator allEntities*(root: Entity): Entity = + var queue = @[root] + while queue.len > 0: + let next = queue.pop + for child in next.children: + queue.add child + yield next
--- a/tests/test_mesh.nim Mon May 22 19:27:17 2023 +0700 +++ b/tests/test_mesh.nim Tue May 23 01:05:06 2023 +0700 @@ -1,13 +1,19 @@ import semicongine proc main() = + var ent1 = newEntity("hoho", rect()) + var ent2 = newEntity("hehe", ent1) + var myScene = newScene("hi", ent2) + myScene.root.transform = translate3d(0.2'f32, 0'f32, 0'f32) + myScene.root.children[0].transform = translate3d(0'f32, 0.2'f32, 0'f32) var scenes = [ - loadScene("default_cube.glb", "1"), - loadScene("default_cube1.glb", "3"), - loadScene("default_cube2.glb", "4"), - loadScene("flat.glb", "5"), + # loadScene("default_cube.glb", "1"), + # loadScene("default_cube1.glb", "3"), + # loadScene("default_cube2.glb", "4"), + # loadScene("flat.glb", "5"), loadScene("tutorialk-donat.glb", "6"), - loadScene("personv3.glb", "2"), + # myScene, + # loadScene("personv3.glb", "2"), ] var engine = initEngine("Test meshes") @@ -15,37 +21,46 @@ vertexInput = @[ attr[Vec3f]("position", memoryPerformanceHint=PreferFastRead), attr[uint8]("material", memoryPerformanceHint=PreferFastRead), + attr[Vec2f]("texcoord_0", memoryPerformanceHint=PreferFastRead), + attr[Mat4]("transform", memoryPerformanceHint=PreferFastWrite, perInstance=true), ] - vertexOutput = @[attr[Vec4f]("vertexColor")] + vertexOutput = @[attr[Vec4f]("vertexColor"), attr[Vec2f]("colorTexCoord")] fragOutput = @[attr[Vec4f]("color")] uniforms = @[ attr[Mat4]("projection"), attr[Mat4]("view"), - attr[Mat4]("model"), attr[Vec4f]("material_color", arrayCount=16), ] + samplers = @[ + attr[Sampler2DType]("material_color_texture", arrayCount=1), + ] vertexCode = compileGlslShader( stage=VK_SHADER_STAGE_VERTEX_BIT, inputs=vertexInput, outputs=vertexOutput, uniforms=uniforms, - main="""gl_Position = Uniforms.projection * Uniforms.view * Uniforms.model * vec4(position, 1.0); vertexColor = Uniforms.material_color[material];""" + samplers=samplers, + main=""" +gl_Position = vec4(position, 1.0) * (transform * Uniforms.view * Uniforms.projection); +vertexColor = Uniforms.material_color[material]; +colorTexCoord = texcoord_0; +""" ) fragmentCode = compileGlslShader( stage=VK_SHADER_STAGE_FRAGMENT_BIT, inputs=vertexOutput, outputs=fragOutput, uniforms=uniforms, - main="""color = vertexColor;""" + samplers=samplers, + main="""color = texture(material_color_texture[0], colorTexCoord) * vertexColor;""" ) engine.setRenderer(engine.gpuDevice.simpleForwardRenderPass(vertexCode, fragmentCode, clearColor=newVec4f(0, 0, 0, 1))) for scene in scenes.mitems: - engine.addScene(scene, vertexInput) + engine.addScene(scene, vertexInput, transformAttribute="transform") scene.addShaderGlobal("projection", Unit4) scene.addShaderGlobal("view", Unit4) - scene.addShaderGlobal("model", Unit4) var - size = 0.3'f32 + size = 1'f32 elevation = 0'f32 azimut = 0'f32 currentScene = 0 @@ -78,10 +93,8 @@ "view", scale3d(size, size, size) * rotate3d(elevation, newVec3f(1, 0, 0)) * rotate3d(azimut, Yf32) ) - scenes[currentScene].setShaderGlobal("model", Unit4f32) engine.renderScene(scenes[currentScene]) engine.destroy() - when isMainModule: main()