mirror of
https://github.com/godotengine/godot.git
synced 2025-01-22 10:32:54 -05:00
Implement 2D instance shader parameters
Co-authored-by: kobewi <kobewi4e@gmail.com> Co-authored-by: yesfish <huwpascoe@users.noreply.github.com> Co-authored-by: Álex Román Núñez <eirexe123@gmail.com>
This commit is contained in:
parent
b9437c3938
commit
ceefc0d38a
24 changed files with 626 additions and 168 deletions
|
@ -461,6 +461,13 @@
|
|||
Returns the transform from the local coordinate system of this [CanvasItem] to the [Viewport]s coordinate system.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_instance_shader_parameter" qualifiers="const">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="name" type="StringName" />
|
||||
<description>
|
||||
Get the value of a shader parameter as set on this instance.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_local_mouse_position" qualifiers="const">
|
||||
<return type="Vector2" />
|
||||
<description>
|
||||
|
@ -562,6 +569,16 @@
|
|||
Queues the [CanvasItem] to redraw. During idle time, if [CanvasItem] is visible, [constant NOTIFICATION_DRAW] is sent and [method _draw] is called. This only occurs [b]once[/b] per frame, even if this method has been called multiple times.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_instance_shader_parameter">
|
||||
<return type="void" />
|
||||
<param index="0" name="name" type="StringName" />
|
||||
<param index="1" name="value" type="Variant" />
|
||||
<description>
|
||||
Set the value of a shader uniform for this instance only ([url=$DOCS_URL/tutorials/shaders/shader_reference/shading_language.html#per-instance-uniforms]per-instance uniform[/url]). See also [method ShaderMaterial.set_shader_parameter] to assign a uniform on all instances using the same [ShaderMaterial].
|
||||
[b]Note:[/b] For a shader uniform to be assignable on a per-instance basis, it [i]must[/i] be defined with [code]instance uniform ...[/code] rather than [code]uniform ...[/code] in the shader code.
|
||||
[b]Note:[/b] [param name] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector).
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_notify_local_transform">
|
||||
<return type="void" />
|
||||
<param index="0" name="enable" type="bool" />
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
Set the value of a shader uniform for this instance only ([url=$DOCS_URL/tutorials/shaders/shader_reference/shading_language.html#per-instance-uniforms]per-instance uniform[/url]). See also [method ShaderMaterial.set_shader_parameter] to assign a uniform on all instances using the same [ShaderMaterial].
|
||||
[b]Note:[/b] For a shader uniform to be assignable on a per-instance basis, it [i]must[/i] be defined with [code]instance uniform ...[/code] rather than [code]uniform ...[/code] in the shader code.
|
||||
[b]Note:[/b] [param name] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector).
|
||||
[b]Note:[/b] Per-instance shader uniforms are currently only available in 3D, so there is no 2D equivalent of this method.
|
||||
[b]Note:[/b] Per-instance shader uniforms are only available in Spatial and CanvasItem shaders, but not for Fog, Sky, or Particles shaders.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
|
|
|
@ -436,6 +436,30 @@
|
|||
[b]Note:[/b] The equivalent node is [CanvasItem].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_get_instance_shader_parameter" qualifiers="const">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="instance" type="RID" />
|
||||
<param index="1" name="parameter" type="StringName" />
|
||||
<description>
|
||||
Returns the value of the per-instance shader uniform from the specified canvas item instance. Equivalent to [method CanvasItem.get_instance_shader_parameter].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_get_instance_shader_parameter_default_value" qualifiers="const">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="instance" type="RID" />
|
||||
<param index="1" name="parameter" type="StringName" />
|
||||
<description>
|
||||
Returns the default value of the per-instance shader uniform from the specified canvas item instance. Equivalent to [method CanvasItem.get_instance_shader_parameter].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_get_instance_shader_parameter_list" qualifiers="const">
|
||||
<return type="Dictionary[]" />
|
||||
<param index="0" name="instance" type="RID" />
|
||||
<description>
|
||||
Returns a dictionary of per-instance shader uniform names of the per-instance shader uniform from the specified canvas item instance.
|
||||
The returned dictionary is in PropertyInfo format, with the keys [code]name[/code], [code]class_name[/code], [code]type[/code], [code]hint[/code], [code]hint_string[/code], and [code]usage[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_reset_physics_interpolation">
|
||||
<return type="void" />
|
||||
<param index="0" name="item" type="RID" />
|
||||
|
@ -524,6 +548,15 @@
|
|||
Sets the index for the [CanvasItem].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_set_instance_shader_parameter">
|
||||
<return type="void" />
|
||||
<param index="0" name="instance" type="RID" />
|
||||
<param index="1" name="parameter" type="StringName" />
|
||||
<param index="2" name="value" type="Variant" />
|
||||
<description>
|
||||
Sets the per-instance shader uniform on the specified canvas item instance. Equivalent to [method CanvasItem.set_instance_shader_parameter].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_set_interpolated">
|
||||
<return type="void" />
|
||||
<param index="0" name="item" type="RID" />
|
||||
|
|
|
@ -727,6 +727,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
|||
|
||||
// Bind per-batch uniforms.
|
||||
material_storage->shaders.canvas_shader.version_set_uniform(CanvasShaderGLES3::BATCH_FLAGS, state.canvas_instance_batches[i].flags, shader_version, variant, specialization);
|
||||
material_storage->shaders.canvas_shader.version_set_uniform(CanvasShaderGLES3::SPECULAR_SHININESS_IN, state.canvas_instance_batches[i].specular_shininess, shader_version, variant, specialization);
|
||||
|
||||
GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
|
||||
Color blend_color = state.canvas_instance_batches[i].blend_color;
|
||||
|
@ -907,15 +908,15 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
|
|||
state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
|
||||
state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
|
||||
|
||||
state.instance_data_array[r_index].pad[0] = 0.0;
|
||||
state.instance_data_array[r_index].pad[1] = 0.0;
|
||||
|
||||
state.instance_data_array[r_index].lights[0] = lights[0];
|
||||
state.instance_data_array[r_index].lights[1] = lights[1];
|
||||
state.instance_data_array[r_index].lights[2] = lights[2];
|
||||
state.instance_data_array[r_index].lights[3] = lights[3];
|
||||
|
||||
state.instance_data_array[r_index].flags = base_flags;
|
||||
state.instance_data_array[r_index].instance_uniforms_ofs = p_item->instance_allocated_shader_uniforms_offset;
|
||||
|
||||
state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED | BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED)); // Reset on each command for safety, keep canvastexture binding config.
|
||||
|
||||
Color blend_color = base_color;
|
||||
GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode;
|
||||
|
@ -2387,10 +2388,10 @@ void RasterizerCanvasGLES3::_prepare_canvas_texture(RID p_texture, RS::CanvasIte
|
|||
state.canvas_instance_batches[state.current_batch_index].flags &= ~BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
|
||||
}
|
||||
|
||||
state.instance_data_array[r_index].specular_shininess = uint32_t(CLAMP(ct->specular_color.a * 255.0, 0, 255)) << 24;
|
||||
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.b * 255.0, 0, 255)) << 16;
|
||||
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.g * 255.0, 0, 255)) << 8;
|
||||
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.r * 255.0, 0, 255));
|
||||
state.canvas_instance_batches[state.current_batch_index].specular_shininess = uint32_t(CLAMP(ct->specular_color.a * 255.0, 0, 255)) << 24;
|
||||
state.canvas_instance_batches[state.current_batch_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.b * 255.0, 0, 255)) << 16;
|
||||
state.canvas_instance_batches[state.current_batch_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.g * 255.0, 0, 255)) << 8;
|
||||
state.canvas_instance_batches[state.current_batch_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.r * 255.0, 0, 255));
|
||||
|
||||
r_texpixel_size.x = 1.0 / float(size_cache.x);
|
||||
r_texpixel_size.y = 1.0 / float(size_cache.y);
|
||||
|
|
|
@ -227,7 +227,7 @@ public:
|
|||
};
|
||||
};
|
||||
uint32_t flags;
|
||||
uint32_t specular_shininess;
|
||||
uint32_t instance_uniforms_ofs;
|
||||
uint32_t lights[4];
|
||||
};
|
||||
|
||||
|
@ -279,6 +279,9 @@ public:
|
|||
uint32_t primitive_points = 0;
|
||||
|
||||
uint32_t flags = 0;
|
||||
uint32_t specular_shininess = 0.0;
|
||||
|
||||
bool lights_disabled = false;
|
||||
};
|
||||
|
||||
// DataBuffer contains our per-frame data. I.e. the resources that are updated each frame.
|
||||
|
|
|
@ -83,7 +83,7 @@ layout(location = 15) in highp uvec4 attrib_H;
|
|||
#endif
|
||||
|
||||
#define read_draw_data_flags attrib_G.z
|
||||
#define read_draw_data_specular_shininess attrib_G.w
|
||||
#define read_draw_data_instance_offset attrib_G.w
|
||||
#define read_draw_data_lights attrib_H
|
||||
|
||||
// Varyings so the per-instance info can be used in the fragment shader
|
||||
|
@ -142,7 +142,7 @@ void main() {
|
|||
#endif // !USE_ATTRIBUTES
|
||||
#endif // USE_PRIMITIVE
|
||||
|
||||
varying_F = uvec2(read_draw_data_flags, read_draw_data_specular_shininess);
|
||||
varying_F = uvec2(read_draw_data_flags, read_draw_data_instance_offset);
|
||||
varying_G = read_draw_data_lights;
|
||||
|
||||
vec4 instance_custom = vec4(0.0);
|
||||
|
@ -325,7 +325,7 @@ flat in vec4 varying_E;
|
|||
flat in uvec2 varying_F;
|
||||
flat in uvec4 varying_G;
|
||||
#define read_draw_data_flags varying_F.x
|
||||
#define read_draw_data_specular_shininess varying_F.y
|
||||
#define read_draw_data_instance_offset varying_F.y
|
||||
#define read_draw_data_lights varying_G
|
||||
|
||||
#ifndef DISABLE_LIGHTING
|
||||
|
@ -340,6 +340,7 @@ uniform sampler2D specular_texture; //texunit:-7
|
|||
uniform sampler2D color_texture; //texunit:0
|
||||
|
||||
uniform mediump uint batch_flags;
|
||||
uniform highp uint specular_shininess_in;
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
||||
|
@ -660,7 +661,7 @@ void main() {
|
|||
|
||||
if (specular_shininess_used || (using_light && normal_used && bool(batch_flags & BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
|
||||
specular_shininess = texture(specular_texture, uv);
|
||||
specular_shininess *= godot_unpackUnorm4x8(read_draw_data_specular_shininess);
|
||||
specular_shininess *= godot_unpackUnorm4x8(specular_shininess_in);
|
||||
specular_shininess_used = true;
|
||||
} else {
|
||||
specular_shininess = vec4(1.0);
|
||||
|
|
|
@ -1193,6 +1193,7 @@ MaterialStorage::MaterialStorage() {
|
|||
actions.render_mode_defines["world_vertex_coords"] = "#define USE_WORLD_VERTEX_COORDS\n";
|
||||
|
||||
actions.global_buffer_array_variable = "global_shader_uniforms";
|
||||
actions.instance_uniform_index_variable = "read_draw_data_instance_offset";
|
||||
|
||||
shaders.compiler_canvas.initialize(actions);
|
||||
}
|
||||
|
|
|
@ -552,6 +552,60 @@ int CanvasItem::get_light_mask() const {
|
|||
return light_mask;
|
||||
}
|
||||
|
||||
const StringName *CanvasItem::_instance_shader_parameter_get_remap(const StringName &p_name) const {
|
||||
StringName *r = instance_shader_parameter_property_remap.getptr(p_name);
|
||||
if (!r) {
|
||||
String s = p_name;
|
||||
if (s.begins_with("instance_shader_parameters/")) {
|
||||
StringName name = s.trim_prefix("instance_shader_parameters/");
|
||||
instance_shader_parameter_property_remap[p_name] = name;
|
||||
return instance_shader_parameter_property_remap.getptr(p_name);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CanvasItem::_set(const StringName &p_name, const Variant &p_value) {
|
||||
const StringName *r = _instance_shader_parameter_get_remap(p_name);
|
||||
if (r) {
|
||||
set_instance_shader_parameter(*r, p_value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CanvasItem::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
const StringName *r = _instance_shader_parameter_get_remap(p_name);
|
||||
if (r) {
|
||||
r_ret = get_instance_shader_parameter(*r);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CanvasItem::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
List<PropertyInfo> pinfo;
|
||||
RS::get_singleton()->canvas_item_get_instance_shader_parameter_list(get_canvas_item(), &pinfo);
|
||||
|
||||
for (PropertyInfo &pi : pinfo) {
|
||||
bool has_def_value = false;
|
||||
Variant def_value = RS::get_singleton()->canvas_item_get_instance_shader_parameter_default_value(get_canvas_item(), pi.name);
|
||||
if (def_value.get_type() != Variant::NIL) {
|
||||
has_def_value = true;
|
||||
}
|
||||
if (instance_shader_parameters.has(pi.name)) {
|
||||
pi.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | (has_def_value ? (PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED) : PROPERTY_USAGE_NONE);
|
||||
} else {
|
||||
pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); // Do not save if not changed.
|
||||
}
|
||||
|
||||
pi.name = "instance_shader_parameters/" + pi.name;
|
||||
p_list->push_back(pi);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasItem::item_rect_changed(bool p_size_changed) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
if (p_size_changed) {
|
||||
|
@ -1082,6 +1136,26 @@ void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
|
|||
RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
|
||||
}
|
||||
|
||||
void CanvasItem::set_instance_shader_parameter(const StringName &p_name, const Variant &p_value) {
|
||||
if (p_value.get_type() == Variant::NIL) {
|
||||
Variant def_value = RS::get_singleton()->canvas_item_get_instance_shader_parameter_default_value(get_canvas_item(), p_name);
|
||||
RS::get_singleton()->canvas_item_set_instance_shader_parameter(get_canvas_item(), p_name, def_value);
|
||||
instance_shader_parameters.erase(p_value);
|
||||
} else {
|
||||
instance_shader_parameters[p_name] = p_value;
|
||||
if (p_value.get_type() == Variant::OBJECT) {
|
||||
RID tex_id = p_value;
|
||||
RS::get_singleton()->canvas_item_set_instance_shader_parameter(get_canvas_item(), p_name, tex_id);
|
||||
} else {
|
||||
RS::get_singleton()->canvas_item_set_instance_shader_parameter(get_canvas_item(), p_name, p_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variant CanvasItem::get_instance_shader_parameter(const StringName &p_name) const {
|
||||
return RS::get_singleton()->canvas_item_get_instance_shader_parameter(get_canvas_item(), p_name);
|
||||
}
|
||||
|
||||
bool CanvasItem::get_use_parent_material() const {
|
||||
ERR_READ_THREAD_GUARD_V(false);
|
||||
return use_parent_material;
|
||||
|
@ -1244,6 +1318,9 @@ void CanvasItem::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_material", "material"), &CanvasItem::set_material);
|
||||
ClassDB::bind_method(D_METHOD("get_material"), &CanvasItem::get_material);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_instance_shader_parameter", "name", "value"), &CanvasItem::set_instance_shader_parameter);
|
||||
ClassDB::bind_method(D_METHOD("get_instance_shader_parameter", "name"), &CanvasItem::get_instance_shader_parameter);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
|
||||
ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
|
||||
|
||||
|
|
|
@ -116,6 +116,8 @@ private:
|
|||
TextureRepeat texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
|
||||
|
||||
Ref<Material> material;
|
||||
mutable HashMap<StringName, Variant> instance_shader_parameters;
|
||||
mutable HashMap<StringName, StringName> instance_shader_parameter_property_remap;
|
||||
|
||||
mutable Transform2D global_transform;
|
||||
mutable MTFlag global_invalid;
|
||||
|
@ -150,8 +152,13 @@ private:
|
|||
void _update_texture_filter_changed(bool p_propagate);
|
||||
|
||||
void _notify_transform_deferred();
|
||||
const StringName *_instance_shader_parameter_get_remap(const StringName &p_name) const;
|
||||
|
||||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
virtual void _update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat);
|
||||
virtual void _update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter);
|
||||
|
||||
|
@ -355,6 +362,9 @@ public:
|
|||
virtual void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
void set_instance_shader_parameter(const StringName &p_name, const Variant &p_value);
|
||||
Variant get_instance_shader_parameter(const StringName &p_name) const;
|
||||
|
||||
virtual void set_use_parent_material(bool p_use_parent_material);
|
||||
bool get_use_parent_material() const;
|
||||
|
||||
|
|
186
servers/rendering/instance_uniforms.cpp
Normal file
186
servers/rendering/instance_uniforms.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
/**************************************************************************/
|
||||
/* instance_uniforms.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "instance_uniforms.h"
|
||||
|
||||
#include "rendering_server_globals.h"
|
||||
|
||||
void InstanceUniforms::free(RID p_self) {
|
||||
ERR_FAIL_COND(p_self.is_null());
|
||||
|
||||
if (is_allocated()) {
|
||||
RSG::material_storage->global_shader_parameters_instance_free(p_self);
|
||||
_location = -1;
|
||||
}
|
||||
|
||||
_invalidate_items();
|
||||
}
|
||||
|
||||
void InstanceUniforms::materials_start() {
|
||||
_invalidate_items();
|
||||
}
|
||||
|
||||
void InstanceUniforms::materials_append(RID p_material) {
|
||||
ERR_FAIL_COND(p_material.is_null());
|
||||
|
||||
List<RendererMaterialStorage::InstanceShaderParam> params;
|
||||
RSG::material_storage->material_get_instance_shader_parameters(p_material, ¶ms);
|
||||
|
||||
for (const RendererMaterialStorage::InstanceShaderParam &srcp : params) {
|
||||
StringName name = srcp.info.name;
|
||||
if (Item *ptr = _parameters.getptr(name); ptr) {
|
||||
if (!ptr->is_valid()) {
|
||||
_init_param(*ptr, srcp);
|
||||
} else if (ptr->index != srcp.index) {
|
||||
WARN_PRINT("More than one material in instance export the same instance shader uniform '" + srcp.info.name +
|
||||
"', but they do it with different indices. Only the first one (in order) will display correctly.");
|
||||
} else if (ptr->info.type != srcp.info.type) {
|
||||
WARN_PRINT("More than one material in instance export the same instance shader uniform '" + srcp.info.name +
|
||||
"', but they do it with different data types. Only the first one (in order) will display correctly.");
|
||||
}
|
||||
} else {
|
||||
Item i;
|
||||
_init_param(i, srcp);
|
||||
_parameters[name] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InstanceUniforms::materials_finish(RID p_self) {
|
||||
ERR_FAIL_COND_V(p_self.is_null(), false);
|
||||
|
||||
if (_parameters.is_empty()) {
|
||||
if (is_allocated()) {
|
||||
free(p_self);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool should_alloc = !is_allocated();
|
||||
|
||||
if (should_alloc) {
|
||||
_location = RSG::material_storage->global_shader_parameters_instance_allocate(p_self);
|
||||
}
|
||||
|
||||
for (KeyValue<StringName, Item> &kv : _parameters) {
|
||||
Item &i = kv.value;
|
||||
if (i.is_valid()) {
|
||||
RSG::material_storage->global_shader_parameters_instance_update(p_self, i.index, i.value, i.flags);
|
||||
}
|
||||
}
|
||||
|
||||
return should_alloc;
|
||||
}
|
||||
|
||||
Variant InstanceUniforms::get(const StringName &p_name) const {
|
||||
if (const Item *ptr = _parameters.getptr(p_name); ptr) {
|
||||
return ptr->value;
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
||||
void InstanceUniforms::set(RID p_self, const StringName &p_name, const Variant &p_value) {
|
||||
ERR_FAIL_COND(p_self.is_null());
|
||||
ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
|
||||
|
||||
if (Item *ptr = _parameters.getptr(p_name); ptr) {
|
||||
ptr->value = p_value;
|
||||
if (ptr->is_valid()) {
|
||||
RSG::material_storage->global_shader_parameters_instance_update(p_self, ptr->index, ptr->value, ptr->flags);
|
||||
}
|
||||
} else {
|
||||
Item i; // Initialize in materials_finish.
|
||||
i.value = p_value;
|
||||
_parameters[p_name] = i;
|
||||
}
|
||||
}
|
||||
|
||||
Variant InstanceUniforms::get_default(const StringName &p_name) const {
|
||||
if (const Item *ptr = _parameters.getptr(p_name); ptr) {
|
||||
return ptr->default_value;
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
||||
void InstanceUniforms::get_property_list(List<PropertyInfo> &r_parameters) const {
|
||||
Vector<StringName> names;
|
||||
|
||||
// Invalid items won't be saved, but will remain in memory in case of shader compilation failure.
|
||||
for (const KeyValue<StringName, Item> &kv : _parameters) {
|
||||
if (kv.value.is_valid()) {
|
||||
names.push_back(kv.key);
|
||||
}
|
||||
}
|
||||
|
||||
names.sort_custom<StringName::AlphCompare>();
|
||||
|
||||
for (const StringName &n : names) {
|
||||
PropertyInfo pinfo = _parameters[n].info;
|
||||
r_parameters.push_back(pinfo);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceUniforms::_init_param(Item &r_item, const RendererMaterialStorage::InstanceShaderParam &p_param) const {
|
||||
r_item.index = p_param.index;
|
||||
r_item.flags = 0;
|
||||
r_item.info = p_param.info;
|
||||
r_item.default_value = p_param.default_value;
|
||||
|
||||
if (r_item.default_value.get_type() == Variant::NIL) {
|
||||
Callable::CallError cerr;
|
||||
Variant::construct(r_item.info.type, r_item.default_value, nullptr, 0, cerr);
|
||||
}
|
||||
|
||||
if (r_item.value.get_type() == Variant::NIL) {
|
||||
r_item.value = r_item.default_value;
|
||||
}
|
||||
|
||||
if (r_item.info.hint == PROPERTY_HINT_FLAGS) {
|
||||
// HACK: Detect boolean flags count and prevent overhead.
|
||||
switch (r_item.info.hint_string.length()) {
|
||||
case 3: // "x,y"
|
||||
r_item.flags = 1;
|
||||
break;
|
||||
case 5: // "x,y,z"
|
||||
r_item.flags = 2;
|
||||
break;
|
||||
case 7: // "x,y,z,w"
|
||||
r_item.flags = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceUniforms::_invalidate_items() {
|
||||
for (KeyValue<StringName, Item> &kv : _parameters) {
|
||||
kv.value.index = -1;
|
||||
}
|
||||
}
|
73
servers/rendering/instance_uniforms.h
Normal file
73
servers/rendering/instance_uniforms.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/**************************************************************************/
|
||||
/* instance_uniforms.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef INSTANCE_UNIFORMS_H
|
||||
#define INSTANCE_UNIFORMS_H
|
||||
|
||||
#include "core/variant/variant.h"
|
||||
#include "servers/rendering/storage/material_storage.h"
|
||||
|
||||
class InstanceUniforms {
|
||||
public:
|
||||
void free(RID p_self);
|
||||
|
||||
void materials_start();
|
||||
void materials_append(RID p_material);
|
||||
|
||||
// Assign location() to instance offset if materials_finish returns true.
|
||||
bool materials_finish(RID p_self);
|
||||
|
||||
Variant get(const StringName &p_name) const;
|
||||
void set(RID p_self, const StringName &p_name, const Variant &p_value);
|
||||
|
||||
Variant get_default(const StringName &p_name) const;
|
||||
void get_property_list(List<PropertyInfo> &r_parameters) const;
|
||||
|
||||
inline int32_t location() const { return _location; }
|
||||
inline bool is_allocated() const { return _location != -1; }
|
||||
|
||||
private:
|
||||
struct Item {
|
||||
int32_t index = -1;
|
||||
int32_t flags = 0;
|
||||
Variant value;
|
||||
Variant default_value;
|
||||
PropertyInfo info;
|
||||
|
||||
inline bool is_valid() const { return index != -1; }
|
||||
};
|
||||
int32_t _location = -1;
|
||||
HashMap<StringName, Item> _parameters;
|
||||
|
||||
void _init_param(Item &r_item, const RendererMaterialStorage::InstanceShaderParam &p_param) const;
|
||||
void _invalidate_items();
|
||||
};
|
||||
|
||||
#endif // INSTANCE_UNIFORMS_H
|
|
@ -44,6 +44,29 @@
|
|||
// while not making lines appear too soft.
|
||||
const static float FEATHER_SIZE = 1.25f;
|
||||
|
||||
static RendererCanvasCull *_canvas_cull_singleton = nullptr;
|
||||
|
||||
void RendererCanvasCull::_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker) {
|
||||
Item *item = (Item *)p_tracker->userdata;
|
||||
|
||||
switch (p_notification) {
|
||||
case Dependency::DEPENDENCY_CHANGED_MATERIAL: {
|
||||
_canvas_cull_singleton->_item_queue_update(item, true);
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void RendererCanvasCull::_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker) {
|
||||
Item *item = (Item *)p_tracker->userdata;
|
||||
|
||||
if (p_dependency == item->material) {
|
||||
_canvas_cull_singleton->canvas_item_set_material(item->self, RID());
|
||||
}
|
||||
_canvas_cull_singleton->_item_queue_update(item, true);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) {
|
||||
RENDER_TIMESTAMP("Cull CanvasItem Tree");
|
||||
|
||||
|
@ -525,6 +548,8 @@ RID RendererCanvasCull::canvas_item_allocate() {
|
|||
}
|
||||
void RendererCanvasCull::canvas_item_initialize(RID p_rid) {
|
||||
canvas_item_owner.initialize_rid(p_rid);
|
||||
Item *instance = canvas_item_owner.get_or_null(p_rid);
|
||||
instance->self = p_rid;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
|
||||
|
@ -1844,6 +1869,7 @@ void RendererCanvasCull::canvas_item_clear(RID p_item) {
|
|||
ERR_FAIL_NULL(canvas_item);
|
||||
|
||||
canvas_item->clear();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (debug_redraw) {
|
||||
canvas_item->debug_redraw_time = debug_redraw_time;
|
||||
|
@ -1875,6 +1901,7 @@ void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) {
|
|||
ERR_FAIL_NULL(canvas_item);
|
||||
|
||||
canvas_item->material = p_material;
|
||||
_item_queue_update(canvas_item, true);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
|
||||
|
@ -1882,6 +1909,37 @@ void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_
|
|||
ERR_FAIL_NULL(canvas_item);
|
||||
|
||||
canvas_item->use_parent_material = p_enable;
|
||||
_item_queue_update(canvas_item, true);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_instance_shader_parameter(RID p_item, const StringName &p_parameter, const Variant &p_value) {
|
||||
Item *item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(item);
|
||||
|
||||
item->instance_uniforms.set(item->self, p_parameter, p_value);
|
||||
}
|
||||
|
||||
Variant RendererCanvasCull::canvas_item_get_instance_shader_parameter(RID p_item, const StringName &p_parameter) const {
|
||||
const Item *item = const_cast<RendererCanvasCull *>(this)->canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL_V(item, Variant());
|
||||
|
||||
return item->instance_uniforms.get(p_parameter);
|
||||
}
|
||||
|
||||
Variant RendererCanvasCull::canvas_item_get_instance_shader_parameter_default_value(RID p_item, const StringName &p_parameter) const {
|
||||
const Item *item = const_cast<RendererCanvasCull *>(this)->canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL_V(item, Variant());
|
||||
|
||||
return item->instance_uniforms.get_default(p_parameter);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_get_instance_shader_parameter_list(RID p_item, List<PropertyInfo> *p_parameters) const {
|
||||
ERR_FAIL_NULL(p_parameters);
|
||||
const Item *item = const_cast<RendererCanvasCull *>(this)->canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(item);
|
||||
const_cast<RendererCanvasCull *>(this)->update_dirty_items();
|
||||
|
||||
item->instance_uniforms.get_property_list(*p_parameters);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) {
|
||||
|
@ -2411,6 +2469,63 @@ Rect2 RendererCanvasCull::_debug_canvas_item_get_rect(RID p_item) {
|
|||
return canvas_item->get_rect();
|
||||
}
|
||||
|
||||
void RendererCanvasCull::_item_queue_update(Item *p_item, bool p_update_dependencies) {
|
||||
if (p_update_dependencies) {
|
||||
p_item->update_dependencies = true;
|
||||
}
|
||||
|
||||
if (!p_item->update_item.in_list()) {
|
||||
_item_update_list.add(&p_item->update_item);
|
||||
}
|
||||
}
|
||||
|
||||
void RendererCanvasCull::update_dirty_items() {
|
||||
while (_item_update_list.first()) {
|
||||
_update_dirty_item(_item_update_list.first()->self());
|
||||
}
|
||||
|
||||
// Instance updates may affect resources.
|
||||
RSG::utilities->update_dirty_resources();
|
||||
}
|
||||
|
||||
void RendererCanvasCull::_update_dirty_item(Item *p_item) {
|
||||
if (p_item->update_dependencies) {
|
||||
RID material = p_item->material;
|
||||
|
||||
if (p_item->use_parent_material) {
|
||||
Item *parent = canvas_item_owner.get_or_null(p_item->parent);
|
||||
while (parent != nullptr) {
|
||||
material = parent->material;
|
||||
if (!parent->use_parent_material) {
|
||||
break;
|
||||
}
|
||||
parent = canvas_item_owner.get_or_null(parent->parent);
|
||||
}
|
||||
}
|
||||
|
||||
p_item->dependency_tracker.update_begin();
|
||||
|
||||
p_item->instance_uniforms.materials_start();
|
||||
|
||||
if (material.is_valid()) {
|
||||
p_item->instance_uniforms.materials_append(material);
|
||||
RSG::material_storage->material_update_dependency(material, &p_item->dependency_tracker);
|
||||
}
|
||||
|
||||
if (p_item->instance_uniforms.materials_finish(p_item->self)) {
|
||||
p_item->instance_allocated_shader_uniforms_offset = p_item->instance_uniforms.location();
|
||||
}
|
||||
|
||||
p_item->dependency_tracker.update_end();
|
||||
}
|
||||
_item_update_list.remove(&p_item->update_item);
|
||||
p_item->update_dependencies = false;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::update() {
|
||||
update_dirty_items();
|
||||
}
|
||||
|
||||
bool RendererCanvasCull::free(RID p_rid) {
|
||||
if (canvas_owner.owns(p_rid)) {
|
||||
Canvas *canvas = canvas_owner.get_or_null(p_rid);
|
||||
|
@ -2468,11 +2583,9 @@ bool RendererCanvasCull::free(RID p_rid) {
|
|||
visibility_notifier_allocator.free(canvas_item->visibility_notifier);
|
||||
}
|
||||
|
||||
/*
|
||||
if (canvas_item->material) {
|
||||
canvas_item->material->owners.erase(canvas_item);
|
||||
}
|
||||
*/
|
||||
canvas_item_set_material(canvas_item->self, RID());
|
||||
canvas_item->instance_uniforms.free(canvas_item->self);
|
||||
update_dirty_items();
|
||||
|
||||
if (canvas_item->canvas_group != nullptr) {
|
||||
memdelete(canvas_item->canvas_group);
|
||||
|
@ -2634,6 +2747,8 @@ void RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RI
|
|||
}
|
||||
|
||||
RendererCanvasCull::RendererCanvasCull() {
|
||||
_canvas_cull_singleton = this;
|
||||
|
||||
z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
|
||||
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
|
||||
|
||||
|
@ -2646,4 +2761,5 @@ RendererCanvasCull::RendererCanvasCull() {
|
|||
RendererCanvasCull::~RendererCanvasCull() {
|
||||
memfree(z_list);
|
||||
memfree(z_last_list);
|
||||
_canvas_cull_singleton = nullptr;
|
||||
}
|
||||
|
|
|
@ -34,11 +34,16 @@
|
|||
#include "core/templates/paged_allocator.h"
|
||||
#include "renderer_compositor.h"
|
||||
#include "renderer_viewport.h"
|
||||
#include "servers/rendering/instance_uniforms.h"
|
||||
|
||||
class RendererCanvasCull {
|
||||
static void _dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker);
|
||||
static void _dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
|
||||
|
||||
public:
|
||||
struct Item : public RendererCanvasRender::Item {
|
||||
RID parent; // canvas it belongs to
|
||||
RID self;
|
||||
List<Item *>::Element *E;
|
||||
int z_index;
|
||||
bool z_relative;
|
||||
|
@ -71,7 +76,14 @@ public:
|
|||
|
||||
VisibilityNotifierData *visibility_notifier = nullptr;
|
||||
|
||||
Item() {
|
||||
DependencyTracker dependency_tracker;
|
||||
InstanceUniforms instance_uniforms;
|
||||
SelfList<Item> update_item;
|
||||
|
||||
bool update_dependencies = false;
|
||||
|
||||
Item() :
|
||||
update_item(this) {
|
||||
children_order_dirty = true;
|
||||
E = nullptr;
|
||||
z_index = 0;
|
||||
|
@ -85,9 +97,16 @@ public:
|
|||
ysort_xform = Transform2D();
|
||||
ysort_index = 0;
|
||||
ysort_parent_abs_z_index = 0;
|
||||
|
||||
dependency_tracker.userdata = this;
|
||||
dependency_tracker.changed_callback = &RendererCanvasCull::_dependency_changed;
|
||||
dependency_tracker.deleted_callback = &RendererCanvasCull::_dependency_deleted;
|
||||
}
|
||||
};
|
||||
|
||||
void _item_queue_update(Item *p_item, bool p_update_dependencies);
|
||||
SelfList<Item>::List _item_update_list;
|
||||
|
||||
struct ItemIndexSort {
|
||||
_FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
|
||||
return p_left->index < p_right->index;
|
||||
|
@ -267,6 +286,11 @@ public:
|
|||
|
||||
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
|
||||
|
||||
void canvas_item_set_instance_shader_parameter(RID p_item, const StringName &p_parameter, const Variant &p_value);
|
||||
void canvas_item_get_instance_shader_parameter_list(RID p_item, List<PropertyInfo> *p_parameters) const;
|
||||
Variant canvas_item_get_instance_shader_parameter(RID p_item, const StringName &p_parameter) const;
|
||||
Variant canvas_item_get_instance_shader_parameter_default_value(RID p_item, const StringName &p_parameter) const;
|
||||
|
||||
void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable);
|
||||
|
||||
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
|
||||
|
@ -281,6 +305,8 @@ public:
|
|||
RID canvas_light_allocate();
|
||||
void canvas_light_initialize(RID p_rid);
|
||||
|
||||
void update();
|
||||
|
||||
void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
|
||||
void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
|
||||
void canvas_light_set_enabled(RID p_light, bool p_enabled);
|
||||
|
@ -344,6 +370,9 @@ public:
|
|||
void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
|
||||
|
||||
void update_visibility_notifiers();
|
||||
void update_dirty_items();
|
||||
|
||||
void _update_dirty_item(Item *p_item);
|
||||
|
||||
Rect2 _debug_canvas_item_get_rect(RID p_item);
|
||||
|
||||
|
|
|
@ -343,6 +343,8 @@ public:
|
|||
RID material;
|
||||
RID skeleton;
|
||||
|
||||
int32_t instance_allocated_shader_uniforms_offset = -1;
|
||||
|
||||
Item *next = nullptr;
|
||||
|
||||
struct CopyBackBuffer {
|
||||
|
|
|
@ -1785,6 +1785,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
|
|||
actions.base_varying_index = 5;
|
||||
|
||||
actions.global_buffer_array_variable = "global_shader_uniforms.data";
|
||||
actions.instance_uniform_index_variable = "draw_data.instance_uniforms_ofs";
|
||||
|
||||
shader.compiler.initialize(actions);
|
||||
}
|
||||
|
@ -2239,7 +2240,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
|
|||
state.last_instance_index += instance_index;
|
||||
}
|
||||
|
||||
RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info) {
|
||||
RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, uint32_t p_uniforms_ofs, TextureInfo *p_info) {
|
||||
InstanceData *instance_data = &state.instance_data_array[p_index];
|
||||
// Zero out most fields.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -2266,7 +2267,7 @@ RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(
|
|||
instance_data->color_texture_pixel_size[0] = p_info->texpixel_size.width;
|
||||
instance_data->color_texture_pixel_size[1] = p_info->texpixel_size.height;
|
||||
|
||||
instance_data->pad1 = 0;
|
||||
instance_data->instance_uniforms_ofs = p_uniforms_ofs;
|
||||
|
||||
return instance_data;
|
||||
}
|
||||
|
@ -2284,6 +2285,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
Color base_color = p_item->final_modulate;
|
||||
bool use_linear_colors = p_render_target.use_linear_colors;
|
||||
uint32_t base_flags = 0;
|
||||
uint32_t uniforms_ofs = static_cast<uint32_t>(p_item->instance_allocated_shader_uniforms_offset);
|
||||
|
||||
bool reclip = false;
|
||||
|
||||
|
@ -2383,7 +2385,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
r_current_batch->tex_info = tex_info;
|
||||
}
|
||||
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
Rect2 src_rect;
|
||||
Rect2 dst_rect;
|
||||
|
||||
|
@ -2484,7 +2486,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
r_current_batch->tex_info = tex_info;
|
||||
}
|
||||
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
Rect2 src_rect;
|
||||
Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
|
||||
|
@ -2566,7 +2568,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
r_current_batch->render_primitive = _primitive_type_to_render_primitive(polygon->primitive);
|
||||
}
|
||||
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
Color color = base_color;
|
||||
if (use_linear_colors) {
|
||||
|
@ -2626,7 +2628,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
r_current_batch->tex_info = tex_info;
|
||||
}
|
||||
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) {
|
||||
instance_data->points[j * 2 + 0] = primitive->points[j].x;
|
||||
|
@ -2644,7 +2646,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
_add_to_batch(r_index, r_batch_broken, r_current_batch);
|
||||
|
||||
if (primitive->point_count == 4) {
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
for (uint32_t j = 0; j < 3; j++) {
|
||||
int offset = j == 0 ? 0 : 1;
|
||||
|
@ -2687,7 +2689,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
_prepare_batch_texture_info(m->texture, tex_state, tex_info);
|
||||
}
|
||||
r_current_batch->tex_info = tex_info;
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
r_current_batch->mesh_instance_count = 1;
|
||||
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, instance_data->world);
|
||||
|
@ -2714,7 +2716,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
_prepare_batch_texture_info(mm->texture, tex_state, tex_info);
|
||||
}
|
||||
r_current_batch->tex_info = tex_info;
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
r_current_batch->flags |= 1; // multimesh, trails disabled
|
||||
|
||||
|
@ -2736,7 +2738,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
_prepare_batch_texture_info(pt->texture, tex_state, tex_info);
|
||||
}
|
||||
r_current_batch->tex_info = tex_info;
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
uint32_t divisor = 1;
|
||||
r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor);
|
||||
|
@ -2859,7 +2861,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
|||
r_current_batch->tex_info = tex_info;
|
||||
}
|
||||
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
|
||||
InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, uniforms_ofs, tex_info);
|
||||
|
||||
Rect2 src_rect;
|
||||
Rect2 dst_rect;
|
||||
|
|
|
@ -342,7 +342,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|||
struct InstanceData {
|
||||
float world[6];
|
||||
uint32_t flags;
|
||||
uint32_t pad1;
|
||||
uint32_t instance_uniforms_ofs;
|
||||
union {
|
||||
//rect
|
||||
struct {
|
||||
|
@ -605,7 +605,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|||
void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
|
||||
void _render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
|
||||
void _prepare_batch_texture_info(RID p_texture, TextureState &p_state, TextureInfo *p_info);
|
||||
InstanceData *new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info);
|
||||
InstanceData *new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, uint32_t p_uniforms_ofs, TextureInfo *p_info);
|
||||
[[nodiscard]] Batch *_new_batch(bool &r_batch_broken);
|
||||
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch);
|
||||
void _allocate_instance_buffer();
|
||||
|
|
|
@ -23,7 +23,7 @@ struct InstanceData {
|
|||
vec2 world_y;
|
||||
vec2 world_ofs;
|
||||
uint flags;
|
||||
uint pad2;
|
||||
uint instance_uniforms_ofs;
|
||||
#ifdef USE_PRIMITIVE
|
||||
vec2 points[3];
|
||||
vec2 uvs[3];
|
||||
|
|
|
@ -701,7 +701,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
|
|||
geom->geometry_instance->set_use_baked_light(instance->baked_light);
|
||||
geom->geometry_instance->set_use_dynamic_gi(instance->dynamic_gi);
|
||||
geom->geometry_instance->set_use_lightmap(RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index);
|
||||
geom->geometry_instance->set_instance_shader_uniforms_offset(instance->instance_allocated_shader_uniforms_offset);
|
||||
geom->geometry_instance->set_instance_shader_uniforms_offset(instance->instance_uniforms.location());
|
||||
geom->geometry_instance->set_cast_double_sided_shadows(instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED);
|
||||
if (instance->lightmap_sh.size() == 9) {
|
||||
geom->geometry_instance->set_lightmap_capture(instance->lightmap_sh.ptr());
|
||||
|
@ -1636,58 +1636,21 @@ void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, c
|
|||
Instance *instance = instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL(instance);
|
||||
|
||||
ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
|
||||
|
||||
HashMap<StringName, Instance::InstanceShaderParameter>::Iterator E = instance->instance_shader_uniforms.find(p_parameter);
|
||||
|
||||
if (!E) {
|
||||
Instance::InstanceShaderParameter isp;
|
||||
isp.index = -1;
|
||||
isp.info = PropertyInfo();
|
||||
isp.value = p_value;
|
||||
instance->instance_shader_uniforms[p_parameter] = isp;
|
||||
} else {
|
||||
E->value.value = p_value;
|
||||
if (E->value.index >= 0 && instance->instance_allocated_shader_uniforms) {
|
||||
int flags_count = 0;
|
||||
if (E->value.info.hint == PROPERTY_HINT_FLAGS) {
|
||||
// A small hack to detect boolean flags count and prevent overhead.
|
||||
switch (E->value.info.hint_string.length()) {
|
||||
case 3: // "x,y"
|
||||
flags_count = 1;
|
||||
break;
|
||||
case 5: // "x,y,z"
|
||||
flags_count = 2;
|
||||
break;
|
||||
case 7: // "x,y,z,w"
|
||||
flags_count = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//update directly
|
||||
RSG::material_storage->global_shader_parameters_instance_update(p_instance, E->value.index, p_value, flags_count);
|
||||
}
|
||||
}
|
||||
instance->instance_uniforms.set(instance->self, p_parameter, p_value);
|
||||
}
|
||||
|
||||
Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const {
|
||||
const Instance *instance = instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL_V(instance, Variant());
|
||||
|
||||
if (instance->instance_shader_uniforms.has(p_parameter)) {
|
||||
return instance->instance_shader_uniforms[p_parameter].value;
|
||||
}
|
||||
return Variant();
|
||||
return instance->instance_uniforms.get(p_parameter);
|
||||
}
|
||||
|
||||
Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const {
|
||||
const Instance *instance = instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL_V(instance, Variant());
|
||||
|
||||
if (instance->instance_shader_uniforms.has(p_parameter)) {
|
||||
return instance->instance_shader_uniforms[p_parameter].default_value;
|
||||
}
|
||||
return Variant();
|
||||
return instance->instance_uniforms.get_default(p_parameter);
|
||||
}
|
||||
|
||||
void RendererSceneCull::mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) {
|
||||
|
@ -1699,20 +1662,13 @@ uint32_t RendererSceneCull::get_pipeline_compilations(RS::PipelineSource p_sourc
|
|||
}
|
||||
|
||||
void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
|
||||
ERR_FAIL_NULL(p_parameters);
|
||||
const Instance *instance = instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL(instance);
|
||||
|
||||
update_dirty_instances();
|
||||
|
||||
Vector<StringName> names;
|
||||
for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : instance->instance_shader_uniforms) {
|
||||
names.push_back(E.key);
|
||||
}
|
||||
names.sort_custom<StringName::AlphCompare>();
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
PropertyInfo pinfo = instance->instance_shader_uniforms[names[i]].info;
|
||||
p_parameters->push_back(pinfo);
|
||||
}
|
||||
instance->instance_uniforms.get_property_list(*p_parameters);
|
||||
}
|
||||
|
||||
void RendererSceneCull::_update_instance(Instance *p_instance) const {
|
||||
|
@ -4047,34 +4003,6 @@ void RendererSceneCull::render_particle_colliders() {
|
|||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::_update_instance_shader_uniforms_from_material(HashMap<StringName, Instance::InstanceShaderParameter> &isparams, const HashMap<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) const {
|
||||
List<RendererMaterialStorage::InstanceShaderParam> plist;
|
||||
RSG::material_storage->material_get_instance_shader_parameters(p_material, &plist);
|
||||
for (const RendererMaterialStorage::InstanceShaderParam &E : plist) {
|
||||
StringName name = E.info.name;
|
||||
if (isparams.has(name)) {
|
||||
if (isparams[name].info.type != E.info.type) {
|
||||
WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different data types. Only the first one (in order) will display correctly.");
|
||||
}
|
||||
if (isparams[name].index != E.index) {
|
||||
WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different indices. Only the first one (in order) will display correctly.");
|
||||
}
|
||||
continue; //first one found always has priority
|
||||
}
|
||||
|
||||
Instance::InstanceShaderParameter isp;
|
||||
isp.index = E.index;
|
||||
isp.info = E.info;
|
||||
isp.default_value = E.default_value;
|
||||
if (existing_isparams.has(name)) {
|
||||
isp.value = existing_isparams[name].value;
|
||||
} else {
|
||||
isp.value = E.default_value;
|
||||
}
|
||||
isparams[name] = isp;
|
||||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
||||
if (p_instance->update_aabb) {
|
||||
_update_instance_aabb(p_instance);
|
||||
|
@ -4118,7 +4046,8 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
|
||||
bool can_cast_shadows = true;
|
||||
bool is_animated = false;
|
||||
HashMap<StringName, Instance::InstanceShaderParameter> isparams;
|
||||
|
||||
p_instance->instance_uniforms.materials_start();
|
||||
|
||||
if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) {
|
||||
can_cast_shadows = false;
|
||||
|
@ -4129,7 +4058,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
can_cast_shadows = false;
|
||||
}
|
||||
is_animated = RSG::material_storage->material_is_animated(p_instance->material_override);
|
||||
_update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, p_instance->material_override);
|
||||
p_instance->instance_uniforms.materials_append(p_instance->material_override);
|
||||
} else {
|
||||
if (p_instance->base_type == RS::INSTANCE_MESH) {
|
||||
RID mesh = p_instance->base;
|
||||
|
@ -4151,7 +4080,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
is_animated = true;
|
||||
}
|
||||
|
||||
_update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, mat);
|
||||
p_instance->instance_uniforms.materials_append(mat);
|
||||
|
||||
RSG::material_storage->material_update_dependency(mat, &p_instance->dependency_tracker);
|
||||
}
|
||||
|
@ -4182,7 +4111,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
is_animated = true;
|
||||
}
|
||||
|
||||
_update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, mat);
|
||||
p_instance->instance_uniforms.materials_append(mat);
|
||||
|
||||
RSG::material_storage->material_update_dependency(mat, &p_instance->dependency_tracker);
|
||||
}
|
||||
|
@ -4220,7 +4149,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
is_animated = true;
|
||||
}
|
||||
|
||||
_update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, mat);
|
||||
p_instance->instance_uniforms.materials_append(mat);
|
||||
|
||||
RSG::material_storage->material_update_dependency(mat, &p_instance->dependency_tracker);
|
||||
}
|
||||
|
@ -4236,7 +4165,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
if (p_instance->material_overlay.is_valid()) {
|
||||
can_cast_shadows = can_cast_shadows && RSG::material_storage->material_casts_shadows(p_instance->material_overlay);
|
||||
is_animated = is_animated || RSG::material_storage->material_is_animated(p_instance->material_overlay);
|
||||
_update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, p_instance->material_overlay);
|
||||
p_instance->instance_uniforms.materials_append(p_instance->material_overlay);
|
||||
}
|
||||
|
||||
if (can_cast_shadows != geom->can_cast_shadows) {
|
||||
|
@ -4250,41 +4179,9 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const {
|
|||
}
|
||||
|
||||
geom->material_is_animated = is_animated;
|
||||
p_instance->instance_shader_uniforms = isparams;
|
||||
|
||||
if (p_instance->instance_allocated_shader_uniforms != (p_instance->instance_shader_uniforms.size() > 0)) {
|
||||
p_instance->instance_allocated_shader_uniforms = (p_instance->instance_shader_uniforms.size() > 0);
|
||||
if (p_instance->instance_allocated_shader_uniforms) {
|
||||
p_instance->instance_allocated_shader_uniforms_offset = RSG::material_storage->global_shader_parameters_instance_allocate(p_instance->self);
|
||||
ERR_FAIL_NULL(geom->geometry_instance);
|
||||
geom->geometry_instance->set_instance_shader_uniforms_offset(p_instance->instance_allocated_shader_uniforms_offset);
|
||||
|
||||
for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_uniforms) {
|
||||
if (E.value.value.get_type() != Variant::NIL) {
|
||||
int flags_count = 0;
|
||||
if (E.value.info.hint == PROPERTY_HINT_FLAGS) {
|
||||
// A small hack to detect boolean flags count and prevent overhead.
|
||||
switch (E.value.info.hint_string.length()) {
|
||||
case 3: // "x,y"
|
||||
flags_count = 1;
|
||||
break;
|
||||
case 5: // "x,y,z"
|
||||
flags_count = 2;
|
||||
break;
|
||||
case 7: // "x,y,z,w"
|
||||
flags_count = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RSG::material_storage->global_shader_parameters_instance_update(p_instance->self, E.value.index, E.value.value, flags_count);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RSG::material_storage->global_shader_parameters_instance_free(p_instance->self);
|
||||
p_instance->instance_allocated_shader_uniforms_offset = -1;
|
||||
ERR_FAIL_NULL(geom->geometry_instance);
|
||||
geom->geometry_instance->set_instance_shader_uniforms_offset(-1);
|
||||
}
|
||||
if (p_instance->instance_uniforms.materials_finish(p_instance->self)) {
|
||||
geom->geometry_instance->set_instance_shader_uniforms_offset(p_instance->instance_uniforms.location());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4379,10 +4276,7 @@ bool RendererSceneCull::free(RID p_rid) {
|
|||
instance_geometry_set_material_overlay(p_rid, RID());
|
||||
instance_attach_skeleton(p_rid, RID());
|
||||
|
||||
if (instance->instance_allocated_shader_uniforms) {
|
||||
//free the used shader parameters
|
||||
RSG::material_storage->global_shader_parameters_instance_free(instance->self);
|
||||
}
|
||||
instance->instance_uniforms.free(instance->self);
|
||||
update_dirty_instances(); //in case something changed this
|
||||
|
||||
instance_owner.free(p_rid);
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "core/templates/pass_func.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/self_list.h"
|
||||
#include "servers/rendering/instance_uniforms.h"
|
||||
#include "servers/rendering/renderer_scene_occlusion_cull.h"
|
||||
#include "servers/rendering/renderer_scene_render.h"
|
||||
#include "servers/rendering/rendering_method.h"
|
||||
|
@ -460,16 +461,7 @@ public:
|
|||
AABB transformed_aabb;
|
||||
AABB prev_transformed_aabb;
|
||||
|
||||
struct InstanceShaderParameter {
|
||||
int32_t index = -1;
|
||||
Variant value;
|
||||
Variant default_value;
|
||||
PropertyInfo info;
|
||||
};
|
||||
|
||||
HashMap<StringName, InstanceShaderParameter> instance_shader_uniforms;
|
||||
bool instance_allocated_shader_uniforms = false;
|
||||
int32_t instance_allocated_shader_uniforms_offset = -1;
|
||||
InstanceUniforms instance_uniforms;
|
||||
|
||||
//
|
||||
|
||||
|
@ -1095,8 +1087,6 @@ public:
|
|||
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index);
|
||||
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias);
|
||||
|
||||
void _update_instance_shader_uniforms_from_material(HashMap<StringName, Instance::InstanceShaderParameter> &isparams, const HashMap<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) const;
|
||||
|
||||
virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value);
|
||||
virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const;
|
||||
virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const;
|
||||
|
|
|
@ -77,6 +77,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
|
|||
|
||||
RENDER_TIMESTAMP("Prepare Render Frame");
|
||||
RSG::scene->update(); //update scenes stuff before updating instances
|
||||
RSG::canvas->update();
|
||||
|
||||
frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0;
|
||||
|
||||
|
|
|
@ -990,6 +990,11 @@ public:
|
|||
|
||||
FUNC2(canvas_item_set_material, RID, RID)
|
||||
|
||||
FUNC3(canvas_item_set_instance_shader_parameter, RID, const StringName &, const Variant &)
|
||||
FUNC2RC(Variant, canvas_item_get_instance_shader_parameter, RID, const StringName &)
|
||||
FUNC2RC(Variant, canvas_item_get_instance_shader_parameter_default_value, RID, const StringName &)
|
||||
FUNC2C(canvas_item_get_instance_shader_parameter_list, RID, List<PropertyInfo> *)
|
||||
|
||||
FUNC2(canvas_item_set_use_parent_material, RID, bool)
|
||||
|
||||
FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &)
|
||||
|
|
|
@ -9143,7 +9143,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
|
|||
}
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") {
|
||||
if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial" && String(shader_type_identifier) != "canvas_item") {
|
||||
_set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
|
|
@ -2052,6 +2052,12 @@ TypedArray<Dictionary> RenderingServer::_instance_geometry_get_shader_parameter_
|
|||
return convert_property_list(¶ms);
|
||||
}
|
||||
|
||||
TypedArray<Dictionary> RenderingServer::_canvas_item_get_instance_shader_parameter_list(RID p_instance) const {
|
||||
List<PropertyInfo> params;
|
||||
canvas_item_get_instance_shader_parameter_list(p_instance, ¶ms);
|
||||
return convert_property_list(¶ms);
|
||||
}
|
||||
|
||||
TypedArray<Image> RenderingServer::_bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) {
|
||||
TypedArray<RID> mat_overrides;
|
||||
for (int i = 0; i < p_material_overrides.size(); i++) {
|
||||
|
@ -3291,6 +3297,11 @@ void RenderingServer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &RenderingServer::canvas_item_set_material);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_use_parent_material", "item", "enabled"), &RenderingServer::canvas_item_set_use_parent_material);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_instance_shader_parameter", "instance", "parameter", "value"), &RenderingServer::canvas_item_set_instance_shader_parameter);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_get_instance_shader_parameter", "instance", "parameter"), &RenderingServer::canvas_item_get_instance_shader_parameter);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_get_instance_shader_parameter_default_value", "instance", "parameter"), &RenderingServer::canvas_item_get_instance_shader_parameter_default_value);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_get_instance_shader_parameter_list", "instance"), &RenderingServer::_canvas_item_get_instance_shader_parameter_list);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_visibility_notifier", "item", "enable", "area", "enter_callable", "exit_callable"), &RenderingServer::canvas_item_set_visibility_notifier);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_canvas_group_mode", "item", "mode", "clear_margin", "fit_empty", "fit_margin", "blur_mipmaps"), &RenderingServer::canvas_item_set_canvas_group_mode, DEFVAL(5.0), DEFVAL(false), DEFVAL(0.0), DEFVAL(false));
|
||||
|
||||
|
|
|
@ -1546,6 +1546,11 @@ public:
|
|||
|
||||
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
|
||||
|
||||
virtual void canvas_item_set_instance_shader_parameter(RID p_item, const StringName &, const Variant &p_value) = 0;
|
||||
virtual Variant canvas_item_get_instance_shader_parameter(RID p_item, const StringName &) const = 0;
|
||||
virtual Variant canvas_item_get_instance_shader_parameter_default_value(RID p_item, const StringName &) const = 0;
|
||||
virtual void canvas_item_get_instance_shader_parameter_list(RID p_item, List<PropertyInfo> *p_parameters) const = 0;
|
||||
|
||||
virtual void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
|
||||
|
||||
enum CanvasGroupMode {
|
||||
|
@ -1832,6 +1837,7 @@ private:
|
|||
void _mesh_add_surface(RID p_mesh, const Dictionary &p_surface);
|
||||
Dictionary _mesh_get_surface(RID p_mesh, int p_idx);
|
||||
TypedArray<Dictionary> _instance_geometry_get_shader_parameter_list(RID p_instance) const;
|
||||
TypedArray<Dictionary> _canvas_item_get_instance_shader_parameter_list(RID p_item) const;
|
||||
TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size);
|
||||
void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses);
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
Loading…
Reference in a new issue