Mercurial > games > semicongine
changeset 776:002d9c576756
did: preparations to refactor material system, still tons to do
author | Sam <sam@basx.dev> |
---|---|
date | Sun, 23 Jul 2023 19:53:10 +0700 |
parents | b4b3143e3626 |
children | 754835bf175e |
files | src/semicongine.nim src/semicongine/core/buildconfig.nim src/semicongine/engine.nim src/semicongine/material.nim src/semicongine/mesh.nim src/semicongine/renderer.nim src/semicongine/resources/mesh.nim src/semicongine/scene.nim src/semicongine/vulkan/descriptor.nim src/semicongine/vulkan/image.nim tests/test_materials.nim tests/test_vulkan_wrapper.nim |
diffstat | 12 files changed, 164 insertions(+), 94 deletions(-) [+] |
line wrap: on
line diff
--- a/src/semicongine.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine.nim Sun Jul 23 19:53:10 2023 +0700 @@ -7,6 +7,7 @@ import semicongine/collision import semicongine/scene import semicongine/events +import semicongine/material import semicongine/mesh import semicongine/renderer import semicongine/resources @@ -21,6 +22,7 @@ export collision export scene export events +export material export mesh export renderer export resources
--- a/src/semicongine/core/buildconfig.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/core/buildconfig.nim Sun Jul 23 19:53:10 2023 +0700 @@ -50,7 +50,7 @@ const CONFIGHOTRELOADINTERVAL* {.intdefine.}: int = 1000 # log level -const LOGLEVEL {.strdefine.}: string = (when DEBUG: "lvlAll" else: "lvlWarn") +const LOGLEVEL {.strdefine.}: string = (when DEBUG: "lvlWarn" else: "lvlWarn") const ENGINE_LOGLEVEL* = parseEnum[Level](LOGLEVEL) # resource bundleing settings, need to be configured per project
--- a/src/semicongine/engine.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/engine.nim Sun Jul 23 19:53:10 2023 +0700 @@ -106,10 +106,10 @@ engine.renderer.get.destroy() engine.renderer = some(engine.device.initRenderer(renderPass)) -proc addScene*(engine: var Engine, scene: Scene, vertexInput: seq[ShaderAttribute], samplers: seq[ShaderAttribute], transformAttribute="transform") = +proc addScene*(engine: var Engine, scene: Scene, vertexInput: seq[ShaderAttribute], samplers: seq[ShaderAttribute], transformAttribute="transform", materialIndexAttribute="materialIndex") = assert transformAttribute == "" or transformAttribute in map(vertexInput, proc(a: ShaderAttribute): string = a.name) assert engine.renderer.isSome - engine.renderer.get.setupDrawableBuffers(scene, vertexInput, samplers, transformAttribute=transformAttribute) + engine.renderer.get.setupDrawableBuffers(scene, vertexInput, samplers, transformAttribute=transformAttribute, materialIndexAttribute=materialIndexAttribute) proc renderScene*(engine: var Engine, scene: var Scene) = assert engine.state == Running
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/material.nim Sun Jul 23 19:53:10 2023 +0700 @@ -0,0 +1,12 @@ +import std/tables + +import ./core + +type + Material* = ref object + name*: string + index*: int + constants*: Table[string, DataValue] + textures*: Table[string, Texture] + +func `$`*(mat: Material): string = mat.name
--- a/src/semicongine/mesh.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/mesh.nim Sun Jul 23 19:53:10 2023 +0700 @@ -8,6 +8,7 @@ import ./core import ./scene import ./collision +import ./material type MeshIndexType* = enum @@ -18,6 +19,7 @@ Mesh* = ref object of Component instanceCount*: uint32 instanceTransforms*: seq[Mat4] # this should not reside in data["transform"], as we will use data["transform"] to store the final transformation matrix (as derived from the scene-tree) + materials*: seq[string] dirtyInstanceTransforms: bool data: Table[string, DataList] changedAttributes: seq[string]
--- a/src/semicongine/renderer.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/renderer.nim Sun Jul 23 19:53:10 2023 +0700 @@ -1,4 +1,6 @@ import std/options +import std/sequtils +import std/enumerate import std/tables import std/strformat import std/strutils @@ -17,6 +19,7 @@ import ./scene import ./mesh +import ./material type SceneData = object @@ -28,6 +31,7 @@ attributeLocation*: Table[string, MemoryPerformanceHint] attributeBindingNumber*: Table[string, int] transformAttribute: string # name of attribute that is used for per-instance mesh transformation + materialIndexAttribute: string # name of attribute that is used for material selection entityTransformationCache: Table[Mesh, Mat4] # remembers last transformation, avoid to send GPU-updates if no changes descriptorPool*: DescriptorPool descriptorSets*: Table[VkPipeline, seq[DescriptorSet]] @@ -52,12 +56,12 @@ raise newException(Exception, "Unable to create swapchain") result.swapchain = swapchain.get() -proc setupDrawableBuffers*(renderer: var Renderer, scene: Scene, inputs: seq[ShaderAttribute], samplers: seq[ShaderAttribute], transformAttribute="transform") = +proc setupDrawableBuffers*(renderer: var Renderer, scene: Scene, inputs: seq[ShaderAttribute], samplers: seq[ShaderAttribute], transformAttribute="transform", materialIndexAttribute="materialIndex") = assert not (scene in renderer.scenedata) const VERTEX_ATTRIB_ALIGNMENT = 4 # used for buffer alignment - var data = SceneData() + var scenedata = SceneData() - # when mesh transformation are handled through the scenegraph-transformation, set it up here + # if mesh transformation are handled through the scenegraph-transformation, set it up here if transformattribute != "": var hasTransformAttribute = false for input in inputs: @@ -66,7 +70,17 @@ assert getDataType[Mat4]() == input.thetype hasTransformAttribute = true assert hasTransformAttribute - data.transformAttribute = transformAttribute + scenedata.transformAttribute = transformAttribute + + # check if we have support for material indices, if required + if materialIndexAttribute != "": + var hasMaterialIndexAttribute = false + for input in inputs: + if input.name == materialIndexAttribute: + assert getDataType[uint16]() == input.thetype + hasMaterialIndexAttribute = true + assert hasMaterialIndexAttribute + scenedata.materialIndexAttribute = materialIndexAttribute # find all meshes, populate missing attribute values for shader var allMeshes: seq[Mesh] @@ -74,8 +88,16 @@ allMeshes.add mesh for inputAttr in inputs: if not mesh.hasDataFor(inputAttr.name): + warn(&"Mesh is missing data for shader attribute {inputAttr.name}, auto-filling with empty values") mesh.initData(inputAttr) assert mesh.dataType(inputAttr.name) == inputAttr.thetype, &"mesh attribute {inputAttr.name} has type {mesh.dataType(inputAttr.name)} but shader expects {inputAttr.thetype}" + if scenedata.materialIndexAttribute != "" and inputAttr.name == scenedata.materialIndexAttribute: + assert mesh.materials.len == getMeshData[uint16](mesh, scenedata.materialIndexAttribute)[].len + for i, material in enumerate(mesh.materials): + let matIndex = materialIndex(scene, material) + if matIndex < 0: + raise newException(Exception, &"Required material '{material}' not available in scene (available are: {scene.materials.toSeq})") + updateMeshData[uint16](mesh, scenedata.materialIndexAttribute, uint32(i), uint16(matIndex)) # create index buffer if necessary var indicesBufferSize = 0'u64 @@ -91,7 +113,7 @@ indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) indicesBufferSize += mesh.indexDataSize if indicesBufferSize > 0: - data.indexBuffer = renderer.device.createBuffer( + scenedata.indexBuffer = renderer.device.createBuffer( size=indicesBufferSize, usage=[VK_BUFFER_USAGE_INDEX_BUFFER_BIT], requireMappable=false, @@ -108,8 +130,8 @@ perLocationOffsets[hint] = 0 perLocationSizes[hint] = 0 for attribute in inputs: - data.attributeLocation[attribute.name] = attribute.memoryPerformanceHint - data.attributeBindingNumber[attribute.name] = bindingNumber + scenedata.attributeLocation[attribute.name] = attribute.memoryPerformanceHint + scenedata.attributeBindingNumber[attribute.name] = bindingNumber inc bindingNumber # setup one buffer per attribute-location-type for mesh in allMeshes: @@ -120,7 +142,7 @@ perLocationSizes[attribute.memoryPerformanceHint] += mesh.dataSize(attribute.name) for memoryPerformanceHint, bufferSize in perLocationSizes.pairs: if bufferSize > 0: - data.vertexBuffers[memoryPerformanceHint] = renderer.device.createBuffer( + scenedata.vertexBuffers[memoryPerformanceHint] = renderer.device.createBuffer( size=bufferSize, usage=[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT], requireMappable=memoryPerformanceHint==PreferFastWrite, @@ -135,7 +157,7 @@ offsets.add (attribute.name, attribute.memoryPerformanceHint, perLocationOffsets[attribute.memoryPerformanceHint]) var (pdata, size) = mesh.getRawData(attribute.name) if pdata != nil: # no data - data.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint]) + scenedata.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint]) perLocationOffsets[attribute.memoryPerformanceHint] += size if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) @@ -160,15 +182,15 @@ drawable.indexBufferOffset = indexBufferOffset drawable.indexType = mesh.indexType var (pdata, size) = mesh.getRawIndexData() - data.indexBuffer.setData(pdata, size, indexBufferOffset) + scenedata.indexBuffer.setData(pdata, size, indexBufferOffset) indexBufferOffset += size - data.drawables[mesh] = drawable + scenedata.drawables[mesh] = drawable - for material in scene.getMaterials(): + for material in scene.materials: for textureName, texture in material.textures.pairs: - if not data.textures.hasKey(textureName): - data.textures[textureName] = @[] - data.textures[textureName].add renderer.device.uploadTexture(texture) + if not scenedata.textures.hasKey(textureName): + scenedata.textures[textureName] = @[] + scenedata.textures[textureName].add renderer.device.uploadTexture(texture) # setup uniforms and samplers for subpass_i in 0 ..< renderer.renderPass.subpasses.len: @@ -177,9 +199,9 @@ for uniform in pipeline.uniforms: uniformBufferSize += uniform.size if uniformBufferSize > 0: - data.uniformBuffers[pipeline.vk] = newSeq[Buffer]() + scenedata.uniformBuffers[pipeline.vk] = newSeq[Buffer]() for frame_i in 0 ..< renderer.swapchain.inFlightFrames: - data.uniformBuffers[pipeline.vk].add renderer.device.createBuffer( + scenedata.uniformBuffers[pipeline.vk].add renderer.device.createBuffer( size=uniformBufferSize, usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT], requireMappable=true, @@ -191,20 +213,20 @@ var samplercount = 0'u32 for sampler in samplers: samplercount += (if sampler.arrayCount == 0: 1'u32 else: sampler.arrayCount) - poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32(renderer.swapchain.inFlightFrames) * samplercount) + poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32(renderer.swapchain.inFlightFrames) * samplercount * 2) - data.descriptorPool = renderer.device.createDescriptorSetPool(poolsizes) + scenedata.descriptorPool = renderer.device.createDescriptorSetPool(poolsizes) - data.descriptorSets[pipeline.vk] = pipeline.setupDescriptors( - data.descriptorPool, - data.uniformBuffers.getOrDefault(pipeline.vk, @[]), - data.textures, + scenedata.descriptorSets[pipeline.vk] = pipeline.setupDescriptors( + scenedata.descriptorPool, + scenedata.uniformBuffers.getOrDefault(pipeline.vk, @[]), + scenedata.textures, inFlightFrames=renderer.swapchain.inFlightFrames ) for frame_i in 0 ..< renderer.swapchain.inFlightFrames: - data.descriptorSets[pipeline.vk][frame_i].writeDescriptorSet() + scenedata.descriptorSets[pipeline.vk][frame_i].writeDescriptorSet() - renderer.scenedata[scene] = data + renderer.scenedata[scene] = scenedata proc refreshMeshAttributeData(sceneData: var SceneData, mesh: Mesh, attribute: string) = debug &"Refreshing data on mesh {mesh} for {attribute}" @@ -311,20 +333,20 @@ renderer.device.vk.valid proc destroy*(renderer: var Renderer) = - for data in renderer.scenedata.mvalues: - for buffer in data.vertexBuffers.mvalues: + for scenedata in renderer.scenedata.mvalues: + for buffer in scenedata.vertexBuffers.mvalues: assert buffer.vk.valid buffer.destroy() - if data.indexBuffer.vk.valid: - assert data.indexBuffer.vk.valid - data.indexBuffer.destroy() - for pipelineUniforms in data.uniformBuffers.mvalues: + if scenedata.indexBuffer.vk.valid: + assert scenedata.indexBuffer.vk.valid + scenedata.indexBuffer.destroy() + for pipelineUniforms in scenedata.uniformBuffers.mvalues: for buffer in pipelineUniforms.mitems: assert buffer.vk.valid buffer.destroy() - for textures in data.textures.mvalues: + for textures in scenedata.textures.mvalues: for texture in textures.mitems: texture.destroy() - data.descriptorPool.destroy() + scenedata.descriptorPool.destroy() renderer.renderPass.destroy() renderer.swapchain.destroy()
--- a/src/semicongine/resources/mesh.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/resources/mesh.nim Sun Jul 23 19:53:10 2023 +0700 @@ -1,4 +1,5 @@ import std/strutils +import std/enumerate import std/json import std/logging import std/tables @@ -8,6 +9,7 @@ import ../scene import ../mesh +import ../material import ../core import ./image @@ -161,7 +163,7 @@ else: raise newException(Exception, &"Unsupported index data type: {data.thetype}") -proc loadMesh(root: JsonNode, meshNode: JsonNode, mainBuffer: var seq[uint8]): Mesh = +proc loadMesh(root: JsonNode, meshNode: JsonNode, mainBuffer: var seq[uint8], materials: seq[Material]): Mesh = result = Mesh(instanceCount: 1, instanceTransforms: newSeqWith(1, Unit4F32)) # check if and how we use indexes @@ -193,7 +195,7 @@ setInstanceData(result, "transform", newSeqWith(int(result.instanceCount), Unit4F32)) -proc loadNode(root: JsonNode, node: JsonNode, mainBuffer: var seq[uint8]): Entity = +proc loadNode(root: JsonNode, node: JsonNode, mainBuffer: var seq[uint8], materials: seq[Material]): Entity = var name = "<Unknown>" if node.hasKey("name"): name = node["name"].getStr() @@ -233,16 +235,16 @@ # children if node.hasKey("children"): for childNode in node["children"]: - result.add loadNode(root, root["nodes"][childNode.getInt()], mainBuffer) + result.add loadNode(root, root["nodes"][childNode.getInt()], mainBuffer, materials) # mesh if node.hasKey("mesh"): - result["mesh"] = loadMesh(root, root["meshes"][node["mesh"].getInt()], mainBuffer) + result["mesh"] = loadMesh(root, root["meshes"][node["mesh"].getInt()], mainBuffer, materials) -proc loadScene(root: JsonNode, scenenode: JsonNode, mainBuffer: var seq[uint8]): Scene = +proc loadScene(root: JsonNode, scenenode: JsonNode, mainBuffer: var seq[uint8], materials: seq[Material]): Scene = var rootEntity = newEntity("<root>") for nodeId in scenenode["nodes"]: - var node = loadNode(root, root["nodes"][nodeId.getInt()], mainBuffer) + var node = loadNode(root, root["nodes"][nodeId.getInt()], mainBuffer, materials) node.transform = node.transform * scale3d(1'f32, -1'f32, 1'f32) rootEntity.add node @@ -280,63 +282,63 @@ if sampler.hasKey("wrapT"): result.sampler.wrapModeT = SAMPLER_WRAP_MODE_MAP[sampler["wrapS"].getInt()] -proc loadMaterial(root: JsonNode, materialNode: JsonNode, mainBuffer: var seq[uint8]): Material = - result.name = materialNode.getStr("name") +proc loadMaterial(root: JsonNode, materialNode: JsonNode, mainBuffer: var seq[uint8], materialIndex: int): Material = + result = Material(name: materialNode.getStr("name"), index: materialIndex) let pbr = materialNode["pbrMetallicRoughness"] # color - result.data["baseColorFactor"] = DataValue(thetype: Vec4F32) + result.constants["baseColorFactor"] = DataValue(thetype: Vec4F32) if pbr.hasKey("baseColorFactor"): - setValue(result.data["baseColorFactor"], newVec4f( + setValue(result.constants["baseColorFactor"], newVec4f( pbr["baseColorFactor"][0].getFloat(), pbr["baseColorFactor"][1].getFloat(), pbr["baseColorFactor"][2].getFloat(), pbr["baseColorFactor"][3].getFloat(), )) else: - setValue(result.data["baseColorFactor"], newVec4f(1, 1, 1, 1)) + setValue(result.constants["baseColorFactor"], newVec4f(1, 1, 1, 1)) # pbr material constants for factor in ["metallicFactor", "roughnessFactor"]: - result.data[factor] = DataValue(thetype: Float32) + result.constants[factor] = DataValue(thetype: Float32) if pbr.hasKey(factor): - setValue(result.data[factor], float32(pbr[factor].getFloat())) + setValue(result.constants[factor], float32(pbr[factor].getFloat())) else: - setValue(result.data[factor], 0.5'f32) + setValue(result.constants[factor], 0.5'f32) # pbr material textures for texture in ["baseColorTexture", "metallicRoughnessTexture"]: if pbr.hasKey(texture): result.textures[texture] = loadTexture(root, pbr[texture]["index"].getInt(), mainBuffer) - result.data[texture & "Index"] = DataValue(thetype: UInt8) - setValue(result.data[texture & "Index"], pbr[texture].getOrDefault("texCoord").getInt(0).uint8) + result.constants[texture & "Index"] = DataValue(thetype: UInt8) + setValue(result.constants[texture & "Index"], pbr[texture].getOrDefault("texCoord").getInt(0).uint8) else: result.textures[texture] = DEFAULTEXTURE - result.data[texture & "Index"] = DataValue(thetype: UInt8) - setValue(result.data[texture & "Index"], 0'u8) + result.constants[texture & "Index"] = DataValue(thetype: UInt8) + setValue(result.constants[texture & "Index"], 0'u8) # generic material textures for texture in ["normalTexture", "occlusionTexture", "emissiveTexture"]: if materialNode.hasKey(texture): result.textures[texture] = loadTexture(root, materialNode[texture]["index"].getInt(), mainBuffer) - result.data[texture & "Index"] = DataValue(thetype: UInt8) - setValue(result.data[texture & "Index"], materialNode[texture].getOrDefault("texCoord").getInt(0).uint8) + result.constants[texture & "Index"] = DataValue(thetype: UInt8) + setValue(result.constants[texture & "Index"], materialNode[texture].getOrDefault("texCoord").getInt(0).uint8) else: result.textures[texture] = DEFAULTEXTURE - result.data[texture & "Index"] = DataValue(thetype: UInt8) - setValue(result.data[texture & "Index"], 0'u8) + result.constants[texture & "Index"] = DataValue(thetype: UInt8) + setValue(result.constants[texture & "Index"], 0'u8) # emissiv color - result.data["emissiveFactor"] = DataValue(thetype: Vec3F32) + result.constants["emissiveFactor"] = DataValue(thetype: Vec3F32) if materialNode.hasKey("emissiveFactor"): - setValue(result.data["emissiveFactor"], newVec3f( + setValue(result.constants["emissiveFactor"], newVec3f( materialNode["emissiveFactor"][0].getFloat(), materialNode["emissiveFactor"][1].getFloat(), materialNode["emissiveFactor"][2].getFloat(), )) else: - setValue(result.data["emissiveFactor"], newVec3f(1'f32, 1'f32, 1'f32)) + setValue(result.constants["emissiveFactor"], newVec3f(1'f32, 1'f32, 1'f32)) proc readglTF*(stream: Stream): seq[Scene] = var @@ -368,8 +370,9 @@ debug data.structuredContent.pretty for scene in data.structuredContent["scenes"]: - var scene = data.structuredContent.loadScene(scene, data.binaryBufferData) - for materialNode in data.structuredContent["materials"]: - scene.addMaterial loadMaterial(data.structuredContent, materialNode, data.binaryBufferData) + var materials: seq[Material] + for i, materialNode in enumerate(data.structuredContent["materials"]): + materials.add loadMaterial(data.structuredContent, materialNode, data.binaryBufferData, i) + var scene = data.structuredContent.loadScene(scene, data.binaryBufferData, materials) result.add scene
--- a/src/semicongine/scene.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/scene.nim Sun Jul 23 19:53:10 2023 +0700 @@ -7,6 +7,7 @@ import std/typetraits import ./core +import ./material import ./animation type @@ -14,12 +15,14 @@ name*: string root*: Entity shaderGlobals*: Table[string, DataList] - materials: seq[Material] + materials: OrderedTable[string, Material] + #[ Material* = object name*: string textures*: Table[string, Texture] data*: Table[string, DataValue] + ]# Component* = ref object of RootObj entity*: Entity @@ -109,19 +112,25 @@ func newScene*(name: string, root: Entity): Scene = Scene(name: name, root: root) -func getMaterials*(scene: Scene): seq[Material] = scene.materials +func addMaterial*(scene: var Scene, material: Material) = + assert not scene.materials.contains(material.name), &"Material with name '{material.name}' already exists in scene" + for name, value in material.constants.pairs: + scene.shaderGlobals[name] = newDataList(thetype=value.thetype) -func addMaterial*(scene: var Scene, material: Material) = - if scene.materials.len > 0: - assert material.data.keys.toSeq.sorted() == scene.materials[0].data.keys.toSeq.sorted(), &"{material.data.keys.toSeq.sorted()} == {scene.materials[0].data.keys.toSeq.sorted()}" - else: - for name, value in material.data.pairs: - scene.shaderGlobals[name] = newDataList(thetype=value.thetype) - - for name, value in material.data.pairs: + for name, value in material.constants.pairs: scene.shaderGlobals[name].appendValue(value) - scene.materials.add material + scene.materials[material.name] = material + +func materialIndex*(scene: Scene, materialName: string): int = + for name in scene.materials.keys: + if name == materialName: + return result + inc result + return -1 + +func materials*(scene: Scene): auto = + scene.materials.values.toSeq func hash*(scene: Scene): Hash = hash(scene.name)
--- a/src/semicongine/vulkan/descriptor.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/vulkan/descriptor.nim Sun Jul 23 19:53:10 2023 +0700 @@ -106,7 +106,6 @@ assert layout.device.vk.valid assert layout.vk.valid - var layouts: seq[VkDescriptorSetLayout] var descriptorSets = newSeq[VkDescriptorSet](nframes) for i in 0 ..< nframes: @@ -132,6 +131,9 @@ var bufferInfos: seq[VkDescriptorBufferInfo] var i = bindingBase + # need to keep this sequence out of the loop, otherwise it will be + # gc-ed before the final update call and pointers are invalid :( + var imgInfos: seq[seq[VkDescriptorImageInfo]] for descriptor in descriptorSet.layout.descriptors: if descriptor.thetype == Uniform: assert descriptor.buffer.vk.valid @@ -149,6 +151,7 @@ descriptorCount: descriptor.count, pBufferInfo: addr bufferInfos[^1], ) + echo bufferInfos elif descriptor.thetype == ImageSampler: var imgInfo: seq[VkDescriptorImageInfo] for img_i in 0 ..< descriptor.count: @@ -159,6 +162,7 @@ imageView: descriptor.imageviews[img_i].vk, sampler: descriptor.samplers[img_i].vk, ) + imgInfos.add imgInfo descriptorSetWrites.add VkWriteDescriptorSet( sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, dstSet: descriptorSet.vk, @@ -166,7 +170,8 @@ dstArrayElement: 0, descriptorType: descriptor.vkType, descriptorCount: descriptor.count, - pImageInfo: addr imgInfo[0], + pImageInfo: imgInfos[^1].toCPointer, ) inc i + echo descriptorSetWrites descriptorSet.layout.device.vk.vkUpdateDescriptorSets(uint32(descriptorSetWrites.len), descriptorSetWrites.toCPointer, 0, nil)
--- a/src/semicongine/vulkan/image.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/src/semicongine/vulkan/image.nim Sun Jul 23 19:53:10 2023 +0700 @@ -64,7 +64,7 @@ preferAutoFlush=preferAutoFlush ) image.memoryAllocated = true - debug "Allocating memory for image: ", image.width, "x", image.height, "x", image.depth, " bytes of type ", memoryType + debug "Allocating memory for image: ", image.width, "x", image.height, "x", image.depth, ", ", requirements.size, " bytes of type ", memoryType image.memory = image.device.allocate(requirements.size, memoryType) checkVkResult image.device.vk.vkBindImageMemory(image.vk, image.memory.vk, VkDeviceSize(0))
--- a/tests/test_materials.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/tests/test_materials.nim Sun Jul 23 19:53:10 2023 +0700 @@ -4,11 +4,12 @@ import semicongine proc main() = - var scene = newScene("main", root=newEntity("rect", {"mesh": Component(rect())})) + var flag = rect() + var scene = newScene("main", root=newEntity("rect", {"mesh": Component(flag)})) let (RT, WT, PT) = (hexToColorAlpha("A51931").asPixel, hexToColorAlpha("F4F5F8").asPixel, hexToColorAlpha("2D2A4A").asPixel) let # image from memory - t1 = Image(width: 7, height: 5, imagedata: @[ + thai = Image(width: 7, height: 5, imagedata: @[ RT, RT, RT, RT, RT, RT, RT, WT, WT, WT, WT, WT, WT, WT, PT, PT, PT, PT, PT, PT, PT, @@ -17,13 +18,19 @@ ]) let # image from file - t2 = loadImage("flag.png") + swiss = loadImage("flag.png") var sampler = DefaultSampler() sampler.magnification = VK_FILTER_NEAREST sampler.minification = VK_FILTER_NEAREST - scene.addMaterial(Material(name:"my material", textures: {"my_texture": Texture(image: t1, sampler: sampler)}.toTable)) - scene.addMaterial(Material(name:"my material", textures: {"my_texture": Texture(image: t2, sampler: sampler)}.toTable)) + scene.addMaterial(Material(name:"material1", textures: { + "swissflag": Texture(image: swiss, sampler: sampler), + "thaiflag": Texture(image: thai, sampler: sampler), + }.toTable)) + scene.addMaterial(Material(name:"material2", textures: { + "swissflag": Texture(image: thai, sampler: sampler), + "thaiflag": Texture(image: swiss, sampler: sampler), + }.toTable)) scene.addShaderGlobalArray("test2", @[0'f32, 0'f32]) var engine = initEngine("Test materials") @@ -35,7 +42,10 @@ ] vertexOutput = @[attr[Vec2f]("uvout")] uniforms = @[attr[float32]("test2", arrayCount=2)] - samplers = @[attr[Sampler2DType]("my_texture", arrayCount=2)] + samplers = @[ + attr[Sampler2DType]("swissflag", arrayCount=2), + attr[Sampler2DType]("thaiflag", arrayCount=2), + ] fragOutput = @[attr[Vec4f]("color")] vertexCode = compileGlslShader( stage=VK_SHADER_STAGE_VERTEX_BIT, @@ -53,11 +63,11 @@ outputs=fragOutput, main=""" float d = sin(Uniforms.test2[0]) * 0.5 + 0.5; -color = texture(my_texture[0], uvout) * (1 - d) + texture(my_texture[1], uvout) * d; +color = texture(swissflag[1], uvout) * (1 - d) + texture(thaiflag[1], uvout) * d; """ ) engine.setRenderer(engine.gpuDevice.simpleForwardRenderPass(vertexCode, fragmentCode)) - engine.addScene(scene, vertexInput, samplers, transformAttribute="") + engine.addScene(scene, vertexInput, samplers, transformAttribute="", materialIndexAttribute="") var t = cpuTime() while engine.updateInputs() == Running and not engine.keyIsDown(Escape): var d = float32(cpuTime() - t)
--- a/tests/test_vulkan_wrapper.nim Sun Jul 09 17:40:46 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Sun Jul 23 19:53:10 2023 +0700 @@ -126,14 +126,19 @@ for scene in scenes.mitems: scene.addShaderGlobal("time", 0.0'f32) let (R, W) = ([255'u8, 0'u8, 0'u8, 255'u8], [255'u8, 255'u8, 255'u8, 255'u8]) - scene.addMaterial(Material(name: "my_material", textures: {"my_little_texture": Texture(image: Image(width: 5, height: 5, imagedata: @[ - R, R, R, R, R, - R, R, W, R, R, - R, W, W, W, R, - R, R, W, R, R, - R, R, R, R, R, - ]), sampler: sampler)}.toTable)) - engine.addScene(scene, vertexInput, samplers, transformAttribute="") + scene.addMaterial(Material( + name: "my_material", + textures: { + "my_little_texture": Texture(image: Image(width: 5, height: 5, imagedata: @[ + R, R, R, R, R, + R, R, W, R, R, + R, W, W, W, R, + R, R, W, R, R, + R, R, R, R, R, + ]), sampler: sampler) + }.toTable + )) + engine.addScene(scene, vertexInput, samplers, transformAttribute="", materialIndexAttribute="") # MAINLOOP echo "Setup successfull, start rendering"