1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-15 13:51:40 +00:00

Refactored 2D shader and lighting system

-Removed normal/specular properties from nodes
-Create CanvasTexture, which can contain normal/specular channels
-Refactored, optimized and simplified 2D shaders
-Use atlas for light textures.
-Use a shadow atlas for shadow textures.
-Use both items aboves to make light rendering stateless (faster).
-Reorganized uniform sets for more efficiency.
This commit is contained in:
reduz
2020-10-24 12:15:43 -03:00
parent b67ccf1a6f
commit 84d734da0e
48 changed files with 1330 additions and 1471 deletions

View File

@@ -1118,6 +1118,11 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
}
RD::get_singleton()->free(tex->rd_texture);
if (tex->canvas_texture) {
memdelete(tex->canvas_texture);
tex->canvas_texture = nullptr;
}
Vector<RID> proxies_to_update = tex->proxies;
Vector<RID> proxies_to_redirect = by_tex->proxies;
@@ -1125,6 +1130,10 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
tex->proxies = proxies_to_update; //restore proxies, so they can be updated
if (tex->canvas_texture) {
tex->canvas_texture->diffuse = p_texture; //update
}
for (int i = 0; i < proxies_to_update.size(); i++) {
texture_proxy_update(proxies_to_update[i], p_texture);
}
@@ -1193,6 +1202,167 @@ Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {
return texture_2d_get_size(p_proxy);
}
/* CANVAS TEXTURE */
void RasterizerStorageRD::CanvasTexture::clear_sets() {
if (cleared_cache) {
return;
}
for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j])) {
RD::get_singleton()->free(uniform_sets[i][j]);
uniform_sets[i][j] = RID();
}
}
}
cleared_cache = true;
}
RasterizerStorageRD::CanvasTexture::~CanvasTexture() {
clear_sets();
}
RID RasterizerStorageRD::canvas_texture_create() {
return canvas_texture_owner.make_rid(memnew(CanvasTexture));
}
void RasterizerStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
switch (p_channel) {
case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: {
ct->diffuse = p_texture;
} break;
case RS::CANVAS_TEXTURE_CHANNEL_NORMAL: {
ct->normalmap = p_texture;
} break;
case RS::CANVAS_TEXTURE_CHANNEL_SPECULAR: {
ct->specular = p_texture;
} break;
}
ct->clear_sets();
}
void RasterizerStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
ct->specular_color.r = p_specular_color.r;
ct->specular_color.g = p_specular_color.g;
ct->specular_color.b = p_specular_color.b;
ct->specular_color.a = p_shininess;
ct->clear_sets();
}
void RasterizerStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
ct->texture_filter = p_filter;
ct->clear_sets();
}
void RasterizerStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture);
ct->texture_repeat = p_repeat;
ct->clear_sets();
}
bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) {
CanvasTexture *ct = nullptr;
Texture *t = texture_owner.getornull(p_texture);
if (t) {
//regular texture
if (!t->canvas_texture) {
t->canvas_texture = memnew(CanvasTexture);
t->canvas_texture->diffuse = p_texture;
}
ct = t->canvas_texture;
} else {
ct = canvas_texture_owner.getornull(p_texture);
}
if (!ct) {
return false; //invalid texture RID
}
RS::CanvasItemTextureFilter filter = ct->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? ct->texture_filter : p_base_filter;
ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, false);
RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat;
ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false);
RID uniform_set = ct->uniform_sets[filter][repeat];
if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
//create and update
Vector<RD::Uniform> uniforms;
{ //diffuse
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
t = texture_owner.getornull(ct->diffuse);
if (!t) {
u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ct->size_cache = Size2i(1, 1);
} else {
u.ids.push_back(t->rd_texture);
ct->size_cache = Size2i(t->width_2d, t->height_2d);
}
uniforms.push_back(u);
}
{ //normal
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
t = texture_owner.getornull(ct->normalmap);
if (!t) {
u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL));
ct->use_normal_cache = false;
} else {
u.ids.push_back(t->rd_texture);
ct->use_normal_cache = true;
}
uniforms.push_back(u);
}
{ //specular
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
t = texture_owner.getornull(ct->specular);
if (!t) {
u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ct->use_specular_cache = false;
} else {
u.ids.push_back(t->rd_texture);
ct->use_specular_cache = true;
}
uniforms.push_back(u);
}
{ //sampler
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 3;
u.ids.push_back(sampler_rd_get_default(filter, repeat));
uniforms.push_back(u);
}
uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set);
ct->uniform_sets[filter][repeat] = uniform_set;
ct->cleared_cache = false;
}
r_uniform_set = uniform_set;
r_size = ct->size_cache;
r_specular_shininess = ct->specular_color;
r_use_normal = ct->use_normal_cache;
r_use_specular = ct->use_specular_cache;
return true;
}
/* SHADER API */
RID RasterizerStorageRD::shader_create() {
@@ -5842,6 +6012,7 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
//free in reverse dependency order
if (rt->framebuffer.is_valid()) {
RD::get_singleton()->free(rt->framebuffer);
rt->framebuffer_uniform_set = RID(); //chain deleted
}
if (rt->color.is_valid()) {
@@ -5856,10 +6027,7 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy);
}
rt->backbuffer_mipmaps.clear();
if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) {
RD::get_singleton()->free(rt->backbuffer_uniform_set);
}
rt->backbuffer_uniform_set = RID();
rt->backbuffer_uniform_set = RID(); //chain deleted
}
rt->framebuffer = RID();
@@ -5969,6 +6137,11 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) {
rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0);
if (rt->framebuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->framebuffer_uniform_set)) {
//the new one will require the backbuffer.
RD::get_singleton()->free(rt->framebuffer_uniform_set);
rt->framebuffer_uniform_set = RID();
}
//create mipmaps
for (uint32_t i = 1; i < mipmaps_required; i++) {
RenderTarget::BackbufferMipmap mm;
@@ -6066,6 +6239,12 @@ RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) {
return rt->color;
}
RID RasterizerStorageRD::render_target_get_rd_backbuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->backbuffer;
}
void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
@@ -6135,32 +6314,28 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target,
}
}
RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader) {
RID RasterizerStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
return rt->framebuffer_uniform_set;
}
RID RasterizerStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
if (!rt->backbuffer.is_valid()) {
_create_render_target_backbuffer(rt);
}
if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) {
return rt->backbuffer_uniform_set; //if still valid, return/reuse it.
}
//create otherwise
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
u.ids.push_back(rt->backbuffer);
uniforms.push_back(u);
rt->backbuffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, 3);
ERR_FAIL_COND_V(!rt->backbuffer_uniform_set.is_valid(), RID());
return rt->backbuffer_uniform_set;
}
void RasterizerStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
rt->framebuffer_uniform_set = p_uniform_set;
}
void RasterizerStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
rt->backbuffer_uniform_set = p_uniform_set;
}
void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
if (mesh_owner.owns(p_base)) {
Mesh *mesh = mesh_owner.getornull(p_base);
@@ -7192,8 +7367,16 @@ bool RasterizerStorageRD::free(RID p_rid) {
p->rd_texture = RID();
p->rd_texture_srgb = RID();
}
if (t->canvas_texture) {
memdelete(t->canvas_texture);
}
texture_owner.free(p_rid);
} else if (canvas_texture_owner.owns(p_rid)) {
CanvasTexture *ct = canvas_texture_owner.getornull(p_rid);
memdelete(ct);
canvas_texture_owner.free(p_rid);
} else if (shader_owner.owns(p_rid)) {
Shader *shader = shader_owner.getornull(p_rid);
//make material unreference this