mirror of
https://github.com/Relintai/material-maker.git
synced 2024-12-23 21:16:54 +01:00
Optimized 3D preview and buffer nodes
This commit is contained in:
parent
455dcc7fde
commit
3c87f2c491
@ -117,12 +117,13 @@ func get_parameter(n : String):
|
||||
|
||||
func set_parameter(n : String, v) -> void:
|
||||
parameters[n] = v
|
||||
source_changed(0)
|
||||
emit_signal("parameter_changed", n, v)
|
||||
if is_inside_tree():
|
||||
var parameter_def : Dictionary = get_parameter_def(n)
|
||||
if parameter_def.has("type") and parameter_def.type == "float":
|
||||
get_tree().call_group("preview", "on_float_parameter_changed", "p_o%s_%s" % [ str(get_instance_id()), n ], v)
|
||||
else:
|
||||
source_changed(0)
|
||||
|
||||
func notify_output_change(output_index : int) -> void:
|
||||
var targets = get_targets(output_index)
|
||||
|
@ -7,11 +7,16 @@ Texture generator buffers, that render their input in a specific resolution and
|
||||
This is useful when using generators that sample their inputs several times (such as convolutions)
|
||||
"""
|
||||
|
||||
var updated : bool = false
|
||||
var material : ShaderMaterial = null
|
||||
var updating : bool = false
|
||||
var update_again : bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
material = ShaderMaterial.new()
|
||||
material.shader = Shader.new()
|
||||
if !parameters.has("size"):
|
||||
parameters.size = 9
|
||||
add_to_group("preview")
|
||||
|
||||
func get_type() -> String:
|
||||
return "buffer"
|
||||
@ -31,20 +36,51 @@ func get_input_defs() -> Array:
|
||||
func get_output_defs() -> Array:
|
||||
return [ { type="rgba" }, { type="rgba" } ]
|
||||
|
||||
func source_changed(input_port_index : int) -> void:
|
||||
updated = false
|
||||
.source_changed(input_port_index)
|
||||
func source_changed(_input_port_index : int) -> void:
|
||||
if !is_inside_tree():
|
||||
return
|
||||
var context : MMGenContext = MMGenContext.new()
|
||||
var source = {}
|
||||
var source_output = get_source(0)
|
||||
if source_output != null:
|
||||
source = source_output.generator.get_shader_code("uv", source_output.output_index, context)
|
||||
while source is GDScriptFunctionState:
|
||||
source = yield(source, "completed")
|
||||
if source.empty():
|
||||
source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
|
||||
material.shader.code = mm_renderer.generate_shader(source)
|
||||
if source.has("textures"):
|
||||
for k in source.textures.keys():
|
||||
material.set_shader_param(k, source.textures[k])
|
||||
update_buffer()
|
||||
|
||||
func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
|
||||
func on_float_parameter_changed(n : String, v : float) -> void:
|
||||
material.set_shader_param(n, v)
|
||||
update_buffer()
|
||||
|
||||
func update_buffer():
|
||||
update_again = true
|
||||
if !updating:
|
||||
updating = true
|
||||
while update_again:
|
||||
update_again = false
|
||||
var result = mm_renderer.render_material(material, pow(2, parameters.size))
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
if !update_again:
|
||||
result.copy_to_texture(texture)
|
||||
result.release()
|
||||
updating = false
|
||||
|
||||
func __get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
|
||||
var source = get_source(0)
|
||||
if source != null and !updated:
|
||||
if source != null:
|
||||
var result = source.generator.render(source.output_index, pow(2, parameters.size))
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
result.copy_to_texture(texture)
|
||||
result.release()
|
||||
texture.flags = Texture.FLAG_MIPMAPS
|
||||
updated = true
|
||||
var rv = ._get_shader_code_lod(uv, output_index, context, 0 if output_index == 0 else parameters.lod)
|
||||
while rv is GDScriptFunctionState:
|
||||
rv = yield(rv, "completed")
|
||||
|
@ -5,7 +5,11 @@ class_name MMGenMaterial
|
||||
var export_paths = {}
|
||||
|
||||
var material : SpatialMaterial
|
||||
var shader_materials = {}
|
||||
var need_update = {}
|
||||
var generated_textures = {}
|
||||
var updating : bool = false
|
||||
var update_again : bool = false
|
||||
|
||||
const TEXTURE_LIST = [
|
||||
{ port=0, texture="albedo", sources=[0] },
|
||||
@ -38,7 +42,11 @@ const TEXTURE_SIZE_DEFAULT = 10 # 1024x1024
|
||||
func _ready() -> void:
|
||||
for t in TEXTURE_LIST:
|
||||
generated_textures[t.texture] = null
|
||||
need_update[t.texture] = true
|
||||
shader_materials[t.texture] = ShaderMaterial.new()
|
||||
shader_materials[t.texture].shader = Shader.new()
|
||||
material = SpatialMaterial.new()
|
||||
add_to_group("preview")
|
||||
|
||||
func can_be_deleted() -> bool:
|
||||
return false
|
||||
@ -74,34 +82,63 @@ func set_parameter(p, v) -> void:
|
||||
func source_changed(input_index : int) -> void:
|
||||
for t in TEXTURE_LIST:
|
||||
if t.has("sources") and t.sources.find(input_index) != -1:
|
||||
generated_textures[t.texture] = null
|
||||
need_update[t.texture] = true
|
||||
update_preview()
|
||||
|
||||
func render_textures() -> void:
|
||||
for t in TEXTURE_LIST:
|
||||
var texture = null
|
||||
var result
|
||||
if t.has("port"):
|
||||
if generated_textures[t.texture] != null:
|
||||
if !need_update[t.texture]:
|
||||
continue
|
||||
result = render(t.port, get_image_size())
|
||||
var context : MMGenContext = MMGenContext.new()
|
||||
var source = get_shader_code("uv", t.port, context)
|
||||
while source is GDScriptFunctionState:
|
||||
source = yield(source, "completed")
|
||||
if source.empty():
|
||||
source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
|
||||
shader_materials[t.texture].shader.code = mm_renderer.generate_shader(source)
|
||||
if source.has("textures"):
|
||||
for k in source.textures.keys():
|
||||
shader_materials[t.texture].set_shader_param(k, source.textures[k])
|
||||
result = mm_renderer.render_material(shader_materials[t.texture], get_image_size())
|
||||
else:
|
||||
generated_textures[t.texture] = null
|
||||
need_update[t.texture] = false
|
||||
continue
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
texture = ImageTexture.new()
|
||||
if generated_textures[t.texture] == null:
|
||||
generated_textures[t.texture] = ImageTexture.new()
|
||||
var texture = generated_textures[t.texture]
|
||||
result.copy_to_texture(texture)
|
||||
result.release()
|
||||
# To work, this must be set after calling `copy_to_texture()`
|
||||
texture.flags |= ImageTexture.FLAG_ANISOTROPIC_FILTER
|
||||
|
||||
# Disable filtering for small textures, as they're considered to be used
|
||||
# for a pixel art style
|
||||
if texture.get_size().x <= 128:
|
||||
texture.flags ^= ImageTexture.FLAG_FILTER
|
||||
need_update[t.texture] = false
|
||||
|
||||
generated_textures[t.texture] = texture
|
||||
func on_float_parameter_changed(n : String, v : float) -> void:
|
||||
var image_size = get_image_size()
|
||||
for t in TEXTURE_LIST:
|
||||
if generated_textures[t.texture] != null:
|
||||
shader_materials[t.texture].set_shader_param(n, v)
|
||||
update_again = true
|
||||
if !updating:
|
||||
updating = true
|
||||
while update_again:
|
||||
update_again = false
|
||||
for t in TEXTURE_LIST:
|
||||
if generated_textures[t.texture] != null:
|
||||
var result = mm_renderer.render_material(shader_materials[t.texture], image_size)
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
result.copy_to_texture(generated_textures[t.texture])
|
||||
result.release()
|
||||
updating = false
|
||||
|
||||
func update_materials(material_list) -> void:
|
||||
render_textures()
|
||||
|
@ -5,19 +5,24 @@ class_name MMGenRenderer
|
||||
export(String) var debug_path = ""
|
||||
var debug_file_index : int = 0
|
||||
|
||||
var common_shader : String
|
||||
|
||||
var rendering : bool = false
|
||||
|
||||
signal done
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
$ColorRect.material = $ColorRect.material.duplicate(true)
|
||||
var file = File.new()
|
||||
file.open("res://addons/material_maker/common.shader", File.READ)
|
||||
common_shader = file.get_as_text()
|
||||
|
||||
static func generate_shader(src_code) -> String:
|
||||
func generate_shader(src_code) -> String:
|
||||
var code
|
||||
code = "shader_type canvas_item;\n"
|
||||
code += "render_mode blend_disabled;\n"
|
||||
var file = File.new()
|
||||
file.open("res://addons/material_maker/common.shader", File.READ)
|
||||
code += file.get_as_text()
|
||||
code += common_shader
|
||||
code += "\n"
|
||||
if src_code.has("textures"):
|
||||
for t in src_code.textures.keys():
|
||||
@ -38,13 +43,11 @@ static func generate_shader(src_code) -> String:
|
||||
code += shader_code
|
||||
return code
|
||||
|
||||
static func generate_combined_shader(red_code, green_code, blue_code) -> String:
|
||||
func generate_combined_shader(red_code, green_code, blue_code) -> String:
|
||||
var code
|
||||
code = "shader_type canvas_item;\n"
|
||||
code += "render_mode blend_disabled;\n"
|
||||
var file = File.new()
|
||||
file.open("res://addons/material_maker/common.shader", File.READ)
|
||||
code += file.get_as_text()
|
||||
code += common_shader
|
||||
code += "\n"
|
||||
var globals = []
|
||||
var textures = {}
|
||||
@ -84,6 +87,22 @@ func setup_material(shader_material, textures, shader_code) -> void:
|
||||
shader_material.set_shader_param(k+"_tex", textures[k])
|
||||
shader_material.shader.code = shader_code
|
||||
|
||||
func render_material(material, render_size) -> Object:
|
||||
while rendering:
|
||||
yield(self, "done")
|
||||
rendering = true
|
||||
var shader_material = $ColorRect.material
|
||||
size = Vector2(render_size, render_size)
|
||||
$ColorRect.rect_position = Vector2(0, 0)
|
||||
$ColorRect.rect_size = size
|
||||
$ColorRect.material = material
|
||||
render_target_update_mode = Viewport.UPDATE_ONCE
|
||||
update_worlds()
|
||||
yield(get_tree(), "idle_frame")
|
||||
yield(get_tree(), "idle_frame")
|
||||
$ColorRect.material = shader_material
|
||||
return self
|
||||
|
||||
func render_shader(shader, textures, render_size) -> Object:
|
||||
if debug_path != null and debug_path != "":
|
||||
var file_name = debug_path+str(debug_file_index)+".shader"
|
||||
|
@ -95,7 +95,8 @@ func _on_value_changed(new_value, variable) -> void:
|
||||
ignore_parameter_change = variable
|
||||
generator.set_parameter(variable, new_value)
|
||||
ignore_parameter_change = ""
|
||||
update_shaders()
|
||||
if ! (new_value is float):
|
||||
update_shaders()
|
||||
|
||||
func _on_color_changed(new_color, variable) -> void:
|
||||
ignore_parameter_change = variable
|
||||
|
@ -5,15 +5,12 @@ export(String, MULTILINE) var shader : String = ""
|
||||
var generator : MMGenBase = null
|
||||
|
||||
func set_generator(g : MMGenBase) -> void:
|
||||
if generator != null and is_instance_valid(generator):
|
||||
generator.disconnect("float_param_changed", self, "on_float_param_changed")
|
||||
var source = { defs="", code="", textures={}, type="f", f="1.0" }
|
||||
if is_instance_valid(g):
|
||||
generator = g
|
||||
var param_defs : Array = generator.get_parameter_defs()
|
||||
for c in get_children():
|
||||
c.setup_control(generator, param_defs)
|
||||
generator.connect("float_param_changed", self, "on_float_param_changed")
|
||||
var gen_output_defs = generator.get_output_defs()
|
||||
if ! gen_output_defs.empty():
|
||||
var context : MMGenContext = MMGenContext.new()
|
||||
@ -27,6 +24,9 @@ func set_generator(g : MMGenBase) -> void:
|
||||
for c in get_children():
|
||||
c.setup_control(generator, [])
|
||||
material.shader.code = MMGenBase.generate_preview_shader(source, source.type, shader)
|
||||
if source.has("textures"):
|
||||
for k in source.textures.keys():
|
||||
material.set_shader_param(k, source.textures[k])
|
||||
|
||||
func on_float_parameter_changed(n : String, v : float) -> void:
|
||||
material.set_shader_param(n, v)
|
||||
|
@ -1,9 +1,5 @@
|
||||
extends ViewportContainer
|
||||
|
||||
const ENVIRONMENTS = [
|
||||
"experiment", "lobby", "night", "park", "schelde"
|
||||
]
|
||||
|
||||
const CAMERA_DISTANCE_MIN = 1.0
|
||||
const CAMERA_DISTANCE_MAX = 10.0
|
||||
|
||||
|
@ -3,10 +3,11 @@
|
||||
[ext_resource path="res://material_maker/preview/preview_3d.gd" type="Script" id=1]
|
||||
[ext_resource path="res://material_maker/preview/preview_3d_scene.tscn" type="PackedScene" id=2]
|
||||
|
||||
|
||||
[sub_resource type="World" id=1]
|
||||
|
||||
[node name="Preview3D" type="ViewportContainer"]
|
||||
[node name="Preview3D" type="ViewportContainer" groups=[
|
||||
"preview",
|
||||
]]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
Loading…
Reference in New Issue
Block a user