diff --git a/addons/material_maker/engine/pipeline/compute_shader.gd b/addons/material_maker/engine/pipeline/compute_shader.gd index 0b6104d32..3a73cde62 100644 --- a/addons/material_maker/engine/pipeline/compute_shader.gd +++ b/addons/material_maker/engine/pipeline/compute_shader.gd @@ -113,10 +113,13 @@ func render_loop(rd : RenderingDevice, size : Vector2i, chunk_height : int, unif while y < size.y: var h : int = min(chunk_height, size.y-y) + var rids : RIDs = RIDs.new() + # Create a compute pipeline var pipeline : RID = rd.compute_pipeline_create(shader) if !pipeline.is_valid(): print("Cannot create pipeline") + rids.add(pipeline) var compute_list := rd.compute_list_begin() rd.compute_list_bind_compute_pipeline(compute_list, pipeline) rd.compute_list_bind_uniform_set(compute_list, uniform_set_0, 0) @@ -128,12 +131,8 @@ func render_loop(rd : RenderingDevice, size : Vector2i, chunk_height : int, unif var loop_parameters_values : PackedByteArray = PackedByteArray() loop_parameters_values.resize(4) loop_parameters_values.encode_s32(0, y) - var loop_parameters_buffer : RID = rd.storage_buffer_create(loop_parameters_values.size(), loop_parameters_values) - var loop_parameters_uniform : RDUniform = RDUniform.new() - loop_parameters_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER - loop_parameters_uniform.binding = 0 - loop_parameters_uniform.add_id(loop_parameters_buffer) - var uniform_set_3 : RID = rd.uniform_set_create([loop_parameters_uniform], shader, 3) + var uniform_set_3 : RID = rd.uniform_set_create(create_buffers_uniform_list(rd, [loop_parameters_values], rids), shader, 3) + rids.add(uniform_set_3) rd.compute_list_bind_uniform_set(compute_list, uniform_set_3, 3) if uniform_set_4.is_valid(): @@ -147,9 +146,7 @@ func render_loop(rd : RenderingDevice, size : Vector2i, chunk_height : int, unif #await mm_renderer.get_tree().process_frame rd.sync() - rd.free_rid(uniform_set_3) - rd.free_rid(loop_parameters_buffer) - rd.free_rid(pipeline) + rids.free_rids(rd) #print("End rendering %d-%d (%dms)" % [ y, y+h, render_time ]) @@ -157,10 +154,10 @@ func render_loop(rd : RenderingDevice, size : Vector2i, chunk_height : int, unif func render(texture : MMTexture, size : int) -> bool: var rd : RenderingDevice = await mm_renderer.request_rendering_device(self) - var rids : RIDs = RIDs.new(rd) + var rids : RIDs = RIDs.new() var start_time = Time.get_ticks_msec() var status = await render_2(rd, texture, size, rids) - rids.free_rids() + rids.free_rids(rd) render_time = Time.get_ticks_msec() - start_time mm_renderer.release_rendering_device(self) return status diff --git a/addons/material_maker/engine/pipeline/pipeline.gd b/addons/material_maker/engine/pipeline/pipeline.gd index 9faf8b91a..7c3d684e3 100644 --- a/addons/material_maker/engine/pipeline/pipeline.gd +++ b/addons/material_maker/engine/pipeline/pipeline.gd @@ -37,12 +37,9 @@ class InputTexture: class RIDs: extends RefCounted - var rendering_device : RenderingDevice + var rids : Array[RID] = [] - func _init(rd : RenderingDevice): - rendering_device = rd - func add(rid : RID): if rid.is_valid(): if rids.find(rid) != -1: @@ -52,15 +49,16 @@ class RIDs: else: print("RID is invalid") - func free_rids(): + func free_rids(rd : RenderingDevice): for r in rids: - rendering_device.free_rid(r) + if r.is_valid(): + rd.free_rid(r) const TEXTURE_TYPE : Array[Dictionary] = [ - { decl="r16f", data_format=RenderingDevice.DATA_FORMAT_R16_SFLOAT, image_format=Image.FORMAT_RH }, - { decl="rgba16f", data_format=RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, image_format=Image.FORMAT_RGBAH }, - { decl="r32f", data_format=RenderingDevice.DATA_FORMAT_R32_SFLOAT, image_format=Image.FORMAT_RF }, - { decl="rgba32f", data_format=RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT, image_format=Image.FORMAT_RGBAF } + { decl="r16f", data_format=RenderingDevice.DATA_FORMAT_R16_SFLOAT, image_format=Image.FORMAT_RH, channels=1, bytes_per_channel=2 }, + { decl="rgba16f", data_format=RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, image_format=Image.FORMAT_RGBAH, channels=4, bytes_per_channel=2 }, + { decl="r32f", data_format=RenderingDevice.DATA_FORMAT_R32_SFLOAT, image_format=Image.FORMAT_RF, channels=1, bytes_per_channel=4 }, + { decl="rgba32f", data_format=RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT, image_format=Image.FORMAT_RGBAF, channels=4, bytes_per_channel=4 } ] @@ -187,3 +185,17 @@ func get_texture_uniforms(rd : RenderingDevice, shader : RID, rids : RIDs) -> RI if uniform_set.is_valid(): rids.add(uniform_set) return uniform_set + +func create_buffers_uniform_list(rd : RenderingDevice, buffers : Array[PackedByteArray], rids : RIDs) -> Array[RDUniform]: + var uniform_list : Array[RDUniform] = [] + var binding : int = 0 + for b in buffers: + var buffer : RID = rd.storage_buffer_create(b.size(), b) + rids.add(buffer) + var uniform : RDUniform = RDUniform.new() + uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform.binding = binding + uniform.add_id(buffer) + binding += 1 + uniform_list.append(uniform) + return uniform_list diff --git a/addons/material_maker/engine/pipeline/rendering_pipeline.gd b/addons/material_maker/engine/pipeline/rendering_pipeline.gd new file mode 100644 index 000000000..1dc14e2e3 --- /dev/null +++ b/addons/material_maker/engine/pipeline/rendering_pipeline.gd @@ -0,0 +1,128 @@ +extends MMPipeline +class_name MMRenderingPipeline + +var vertSrc = "#version 450 + +layout(binding = 0, std430) buffer restrict readonly Positions { + vec3 positions[]; +}; +layout(binding = 1, std430) buffer restrict readonly Normals { + vec3 normals[]; +}; +layout(binding = 2, std430) buffer restrict readonly UVs { + vec2 uvs[]; +}; + +void main() { + gl_Position = vec4(uvs[gl_VertexIndex]*2.0-vec2(1.0), 0.0, 1.0); + //gl_Color = vec4(positions[gl_VertexIndex], 1.0); +}" + +var fragSrc = "#version 450 +layout(location = 0) out vec4 outColor; +void main() { + outColor = vec4(1.0, 0.0, 0.0, 1.0); +}" + +var framebuffer : RID +var pipeline : RID +var img_texture : RID + +var clearColors : PackedColorArray = PackedColorArray([Color.TRANSPARENT]) + +func create_target_texture(rd : RenderingDevice, size : Vector2i, texture_type : int, rids : RIDs) -> RID: + var tf = RDTextureFormat.new() + var texture_type_struct : Dictionary = TEXTURE_TYPE[texture_type] + tf.format = texture_type_struct.data_format + tf.height = size.x + tf.width = size.y + tf.usage_bits = RenderingDevice.TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT | RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT + tf.texture_type = RenderingDevice.TEXTURE_TYPE_2D + + var data = PackedByteArray() + data.resize(tf.height*tf.width*texture_type_struct.channels*texture_type_struct.bytes_per_channel) + + var texture_rid : RID = rd.texture_create(tf, RDTextureView.new(), [data]) + rids.add(texture_rid) + + return texture_rid + +func create_framebuffer(rd : RenderingDevice, texture_rid : RID, rids : RIDs) -> RID: + var framebuffer : RID = rd.framebuffer_create([texture_rid]) + rids.add(texture_rid) + + return framebuffer + +func compile_shader(rd : RenderingDevice, vertex_source : String, fragment_source : String, rids : RIDs) -> RID: + var rv : bool = true + var src : RDShaderSource = RDShaderSource.new() + src.source_vertex = vertex_source + src.source_fragment = fragment_source + var spirv : RDShaderSPIRV = rd.shader_compile_spirv_from_source(src) + var shader = RID() + if spirv.compile_error_vertex != "": + var ln : int = 0 + for l in vertex_source.split("\n"): + ln += 1 + print("%4d: %s" % [ ln, l ]) + print("VERTEX SHADER ERROR: "+spirv.compile_error_vertex) + rv = false + if spirv.compile_error_fragment != "": + var ln : int = 0 + for l in fragment_source.split("\n"): + ln += 1 + print("%4d: %s" % [ ln, l ]) + print("FRAGMENT SHADER ERROR: "+spirv.compile_error_fragment) + rv = false + if rv: + shader = rd.shader_create_from_spirv(spirv) + rids.add(shader) + return shader + +func render(mesh : Mesh, size : Vector2i, texture_type : int, target_texture : ImageTexture): + var rd : RenderingDevice = await mm_renderer.request_rendering_device(self) + var rids : RIDs = RIDs.new() + + var shader = compile_shader(rd, vertSrc, fragSrc, rids) + var target_texture_id : RID = create_target_texture(rd, size, texture_type, rids) + var framebuffer : RID = create_framebuffer(rd, target_texture_id, rids) + + var blend : RDPipelineColorBlendState = RDPipelineColorBlendState.new() + blend.attachments.push_back(RDPipelineColorBlendStateAttachment.new()) + pipeline = rd.render_pipeline_create( + shader, + rd.framebuffer_get_format(framebuffer), + -1, + RenderingDevice.RENDER_PRIMITIVE_TRIANGLES, + RDPipelineRasterizationState.new(), + RDPipelineMultisampleState.new(), + RDPipelineDepthStencilState.new(), + blend + ) + + var draw_list : int = rd.draw_list_begin(framebuffer, + RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, + RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, + clearColors) + rd.draw_list_bind_render_pipeline(draw_list, pipeline) + var buffers : Array[PackedByteArray] = [] + buffers.append(mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX].to_byte_array()) + buffers.append(mesh.surface_get_arrays(0)[Mesh.ARRAY_NORMAL].to_byte_array()) + buffers.append(mesh.surface_get_arrays(0)[Mesh.ARRAY_TEX_UV].to_byte_array()) + var uniform_set : RID = rd.uniform_set_create(create_buffers_uniform_list(rd, buffers, rids), shader, 0) + rids.add(uniform_set) + rd.draw_list_bind_uniform_set(draw_list, uniform_set, 0) + print(mesh.surface_get_arrays(0)[0].size()) + rd.draw_list_draw(draw_list, false, 1, mesh.surface_get_arrays(0)[0].size()) + rd.draw_list_end() + rd.submit() + rd.sync() + + var texture_type_struct : Dictionary = TEXTURE_TYPE[texture_type] + var data = rd.texture_get_data(target_texture_id, 0) + var generated_image = Image.create_from_data(size.x, size.y, false, texture_type_struct.image_format, data) + target_texture.set_image(generated_image) + + rids.free_rids(rd) + + mm_renderer.release_rendering_device(self) diff --git a/material_maker/panels/preview_3d/preview_3d.gd b/material_maker/panels/preview_3d/preview_3d.gd index fa5d0c4cc..f5c5e37a2 100644 --- a/material_maker/panels/preview_3d/preview_3d.gd +++ b/material_maker/panels/preview_3d/preview_3d.gd @@ -30,6 +30,7 @@ const MENU = [ { menu="Model/Rotate/Medium", command="set_rotate_model_speed", command_parameter=0.05 }, { menu="Model/Rotate/Fast", command="set_rotate_model_speed", command_parameter=0.1 }, { menu="Model/Generate map/Position", submenu="generate_position_map" }, + { menu="Model/Generate map/Position (new)", submenu="generate_new_position_map" }, { menu="Model/Generate map/Normal", submenu="generate_normal_map" }, { menu="Model/Generate map/Curvature", submenu="generate_curvature_map" }, { menu="Model/Generate map/Ambient Occlusion", submenu="generate_ao_map" }, @@ -258,6 +259,15 @@ func do_generate_map(file_name : String, map : String, image_size : int) -> void map_renderer.queue_free() DisplayServer.clipboard_set("{\"name\":\"image\",\"parameters\":{\"image\":\"%s\"},\"type\":\"image\"}" % file_name) +func do_generate_map_new(file_name : String, map : String, image_size : int) -> void: + var map_renderer = load("res://material_maker/tools/map_renderer/map_renderer.tscn").instantiate() + add_child(map_renderer) + var id = objects.get_child_count()-1 + var object : MeshInstance3D = objects.get_child(id) + await map_renderer.gen_new(object.mesh, map, "save_to_file", [ file_name ], image_size) + map_renderer.queue_free() + DisplayServer.clipboard_set("{\"name\":\"image\",\"parameters\":{\"image\":\"%s\"},\"type\":\"image\"}" % file_name) + func create_menu_map(menu : MMMenuManager.MenuBase, function : String) -> void: menu.clear() for i in range(5): @@ -282,6 +292,15 @@ func generate_position_map(i : int) -> void: func do_generate_position_map(file_name : String, image_size : int) -> void: do_generate_map(file_name, "position", image_size) +func create_menu_generate_new_position_map(menu : MMMenuManager.MenuBase) -> void: + create_menu_map(menu, "generate_new_position_map") + +func generate_new_position_map(i : int) -> void: + generate_map("do_generate_new_position_map", 256 << i) + +func do_generate_new_position_map(file_name : String, image_size : int) -> void: + do_generate_map_new(file_name, "position", image_size) + func create_menu_generate_curvature_map(menu : MMMenuManager.MenuBase) -> void: create_menu_map(menu, "generate_curvature_map") diff --git a/material_maker/tools/map_renderer/map_renderer.gd b/material_maker/tools/map_renderer/map_renderer.gd index 2d00f4429..246b27902 100644 --- a/material_maker/tools/map_renderer/map_renderer.gd +++ b/material_maker/tools/map_renderer/map_renderer.gd @@ -19,6 +19,22 @@ extends Node func _ready(): pass +func gen_new(mesh: Mesh, map : String, renderer_method : String, arguments : Array, map_size = 512) -> void: + var map_generator : MMRenderingPipeline = MMRenderingPipeline.new() + var texture : ImageTexture = ImageTexture.new() + map_generator.render(mesh, Vector2i(map_size, map_size), 3, texture) + match renderer_method: + "save_to_file": + var image = texture.get_image() + if image: + var file_name : String = arguments[0] + print("Saving image to "+file_name) + match file_name.get_extension(): + "png": + image.save_png(file_name) + "exr": + image.save_exr(file_name) + func gen(mesh: Mesh, map : String, renderer_method : String, arguments : Array, map_size = 512) -> void: var bake_passes = { position = { first=position_material, second=dilate_pass1, third=dilate_pass2 }, @@ -29,6 +45,7 @@ func gen(mesh: Mesh, map : String, renderer_method : String, arguments : Array, ao = { first=ao_material, second=dilate_pass1, third=dilate_pass2, map_name="Ambient Occlusion" }, seams = { first=white_material, second=seams_pass1, third=seams_pass2 } } + var passes = bake_passes[map] viewport.size = Vector2(map_size, map_size) if map == "curvature":