diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd')
22 files changed, 1341 insertions, 209 deletions
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp index da30291353..921a7b966e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -29,8 +29,9 @@ /*************************************************************************/ #include "rasterizer_canvas_rd.h" +#include "core/config/project_settings.h" +#include "core/math/geometry_2d.h" #include "core/math/math_funcs.h" -#include "core/project_settings.h" #include "rasterizer_rd.h" void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { @@ -328,7 +329,7 @@ void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_ bool use_normal; bool use_specular; - bool success = storage->canvas_texture_get_unifom_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); + bool success = storage->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); //something odd happened if (!success) { _bind_canvas_texture(p_draw_list, default_canvas_texture, p_base_filter, p_base_repeat, r_last_texture, push_constant, r_texpixel_size); @@ -416,10 +417,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ light_count++; - if (light->mode == RS::CANVAS_LIGHT_MODE_MASK) { - base_flags |= FLAGS_USING_LIGHT_MASK; - } - if (light_count == MAX_LIGHTS_PER_ITEM) { break; } @@ -430,7 +427,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT; } - light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED; + light_mode = (light_count > 0 || using_directional_lights) ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED; PipelineVariants *pipeline_variants = p_pipeline_variants; @@ -691,7 +688,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ #if 0 case Item::Command::TYPE_MESH: { - Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); _set_texture_rect_mode(false); @@ -706,7 +702,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); if (mesh_data) { - for (int j = 0; j < mesh_data->surfaces.size(); j++) { RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing @@ -727,7 +722,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } break; case Item::Command::TYPE_MULTIMESH: { - Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c); RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); @@ -790,7 +784,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ int custom_data_ofs = color_ofs; switch (multi_mesh->color_format) { - case RS::MULTIMESH_COLOR_NONE: { glDisableVertexAttribArray(11); glVertexAttrib4f(11, 1, 1, 1, 1); @@ -811,7 +804,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } switch (multi_mesh->custom_data_format) { - case RS::MULTIMESH_CUSTOM_DATA_NONE: { glDisableVertexAttribArray(12); glVertexAttrib4f(12, 1, 1, 1, 1); @@ -845,7 +837,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } break; case Item::Command::TYPE_PARTICLES: { - Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); @@ -879,7 +870,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } if (!particles->use_local_coords) { - Transform2D inv_xf; inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); @@ -897,7 +887,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ int amount = particles->amount; if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) { - glEnableVertexAttribArray(8); //xform x glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); @@ -1063,10 +1052,19 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ } { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 7; + RID sdf = storage->render_target_get_sdf_texture(p_to_render_target); + u.ids.push_back(sdf); + uniforms.push_back(u); + } + + { //needs samplers for the material (uses custom textures) create them RD::Uniform u; u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 7; + u.binding = 8; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -1087,7 +1085,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 8; + u.binding = 9; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } @@ -1194,51 +1192,84 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, RD::get_singleton()->draw_list_end(); } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { +void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { + r_sdf_used = false; int item_count = 0; //setup canvas state uniforms if needed Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse(); + //setup directional lights if exist + + uint32_t light_count = 0; + uint32_t directional_light_count = 0; { - //update canvas state uniform buffer - State::Buffer state_buffer; + Light *l = p_directional_light_list; + uint32_t index = 0; - Size2i ssize = storage->render_target_get_size(p_to_render_target); + while (l) { + if (index == state.max_lights_per_render) { + l->render_index_cache = -1; + l = l->next_ptr; + continue; + } - Transform screen_transform; - screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); - screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); - _update_transform_to_mat4(screen_transform, state_buffer.screen_transform); - _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); + CanvasLight *clight = canvas_light_owner.getornull(l->light_internal); + if (!clight) { //unused or invalid texture + l->render_index_cache = -1; + l = l->next_ptr; + ERR_CONTINUE(!clight); + } - Transform2D normal_transform = p_canvas_transform; - normal_transform.elements[0].normalize(); - normal_transform.elements[1].normalize(); - normal_transform.elements[2] = Vector2(); - _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); + Vector2 canvas_light_dir = l->xform_cache.elements[1].normalized(); - state_buffer.canvas_modulate[0] = p_modulate.r; - state_buffer.canvas_modulate[1] = p_modulate.g; - state_buffer.canvas_modulate[2] = p_modulate.b; - state_buffer.canvas_modulate[3] = p_modulate.a; + state.light_uniforms[index].position[0] = -canvas_light_dir.x; + state.light_uniforms[index].position[1] = -canvas_light_dir.y; - Size2 render_target_size = storage->render_target_get_size(p_to_render_target); - state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; - state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + _update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix); - state_buffer.time = state.time; - state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel; + state.light_uniforms[index].height = l->height; //0..1 here - RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); + for (int i = 0; i < 4; i++) { + state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255)); + state.light_uniforms[index].color[i] = l->color[i]; + } + + state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate + + if (state.shadow_fb.is_valid()) { + state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth); + state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far; + state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset; + } else { + state.light_uniforms[index].shadow_pixel_size = 1.0; + state.light_uniforms[index].shadow_z_far_inv = 1.0; + state.light_uniforms[index].shadow_y_ofs = 0; + } + + state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT; + state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT; + if (clight->shadow.enabled) { + state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW; + } + + l->render_index_cache = index; + + index++; + l = l->next_ptr; + } + + light_count = index; + directional_light_count = light_count; + using_directional_lights = directional_light_count > 0; } //setup lights if exist { Light *l = p_light_list; - uint32_t index = 0; + uint32_t index = light_count; while (l) { if (index == state.max_lights_per_render) { @@ -1280,7 +1311,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite state.light_uniforms[index].shadow_y_ofs = 0; } - state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT; + state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT; state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT; if (clight->shadow.enabled) { state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW; @@ -1306,9 +1337,65 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite l = l->next_ptr; } - if (index > 0) { - RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * index, &state.light_uniforms[0], true); - } + light_count = index; + } + + if (light_count > 0) { + RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0], true); + } + + { + //update canvas state uniform buffer + State::Buffer state_buffer; + + Size2i ssize = storage->render_target_get_size(p_to_render_target); + + Transform screen_transform; + screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); + screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); + _update_transform_to_mat4(screen_transform, state_buffer.screen_transform); + _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); + + Transform2D normal_transform = p_canvas_transform; + normal_transform.elements[0].normalize(); + normal_transform.elements[1].normalize(); + normal_transform.elements[2] = Vector2(); + _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); + + state_buffer.canvas_modulate[0] = p_modulate.r; + state_buffer.canvas_modulate[1] = p_modulate.g; + state_buffer.canvas_modulate[2] = p_modulate.b; + state_buffer.canvas_modulate[3] = p_modulate.a; + + Size2 render_target_size = storage->render_target_get_size(p_to_render_target); + state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; + state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + + state_buffer.time = state.time; + state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel; + + state_buffer.directional_light_count = directional_light_count; + + Vector2 canvas_scale = p_canvas_transform.get_scale(); + + state_buffer.sdf_to_screen[0] = render_target_size.width / canvas_scale.x; + state_buffer.sdf_to_screen[1] = render_target_size.height / canvas_scale.y; + + state_buffer.screen_to_sdf[0] = 1.0 / state_buffer.sdf_to_screen[0]; + state_buffer.screen_to_sdf[1] = 1.0 / state_buffer.sdf_to_screen[1]; + + Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_to_render_target); + Rect2 sdf_tex_rect(sdf_rect.position / canvas_scale, sdf_rect.size / canvas_scale); + + state_buffer.sdf_to_tex[0] = 1.0 / sdf_tex_rect.size.width; + state_buffer.sdf_to_tex[1] = 1.0 / sdf_tex_rect.size.height; + state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width; + state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height; + + //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale)); + state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5); + + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); } { //default filter/repeat @@ -1345,6 +1432,9 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } + if (md->shader_data->uses_sdf) { + r_sdf_used = true; + } if (md->last_frame != RasterizerRD::singleton->get_frame_number()) { md->last_frame = RasterizerRD::singleton->get_frame_number(); if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { @@ -1439,10 +1529,7 @@ void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable) { cl->shadow.enabled = p_enable; } -void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); - ERR_FAIL_COND(!cl->shadow.enabled); - +void RasterizerCanvasRD::_update_shadow_atlas() { if (state.shadow_fb == RID()) { //ah, we lack the shadow texture.. RD::get_singleton()->free(state.shadow_texture); //erase placeholder @@ -1474,6 +1561,12 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures); } +} +void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND(!cl->shadow.enabled); + + _update_shadow_atlas(); cl->shadow.z_far = p_far; cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2); @@ -1547,18 +1640,182 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons } } +void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND(!cl->shadow.enabled); + + _update_shadow_atlas(); + + Vector2 light_dir = p_light_xform.elements[1].normalized(); + + Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5; + + float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center)); + + Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance); + float distance = to_edge_distance * 2.0 + p_cull_distance; + float half_size = p_clip_rect.size.length() * 0.5; //shadow length, must keep this no matter the angle + + cl->shadow.z_far = distance; + cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2); + + Transform2D to_light_xform; + + to_light_xform[2] = from_pos; + to_light_xform[1] = light_dir; + to_light_xform[0] = -light_dir.tangent(); + + to_light_xform.invert(); + + Vector<Color> cc; + cc.push_back(Color(1, 1, 1, 1)); + + Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + + CameraMatrix projection; + projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); + projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse()); + + ShadowRenderPushConstant push_constant; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + push_constant.projection[y * 4 + x] = projection.matrix[y][x]; + } + } + + push_constant.direction[0] = 0.0; + push_constant.direction[1] = 1.0; + push_constant.z_far = distance; + push_constant.pad = 0; + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + + if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { + instance = instance->next; + continue; + } + + _update_transform_2d_to_mat2x4(to_light_xform * instance->xform_cache, push_constant.modelview); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + + instance = instance->next; + } + + RD::get_singleton()->draw_list_end(); + + Transform2D to_shadow; + to_shadow.elements[0].x = 1.0 / -(half_size * 2.0); + to_shadow.elements[2].x = 0.5; + + cl->shadow.directional_xform = to_shadow * to_light_xform; +} + +void RasterizerCanvasRD::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { + RID fb = storage->render_target_get_sdf_framebuffer(p_render_target); + Rect2i rect = storage->render_target_get_sdf_rect(p_render_target); + + Transform2D to_sdf; + to_sdf.elements[0] *= rect.size.width; + to_sdf.elements[1] *= rect.size.height; + to_sdf.elements[2] = rect.position; + + Transform2D to_clip; + to_clip.elements[0] *= 2.0; + to_clip.elements[1] *= 2.0; + to_clip.elements[2] = -Vector2(1.0, 1.0); + + to_clip = to_clip * to_sdf.affine_inverse(); + + Vector<Color> cc; + cc.push_back(Color(0, 0, 0, 0)); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc); + + CameraMatrix projection; + + ShadowRenderPushConstant push_constant; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + push_constant.projection[y * 4 + x] = projection.matrix[y][x]; + } + } + + push_constant.direction[0] = 0.0; + push_constant.direction[1] = 0.0; + push_constant.z_far = 0; + push_constant.pad = 0; + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + + if (!co || co->sdf_index_array.is_null()) { + instance = instance->next; + continue; + } + + _update_transform_2d_to_mat2x4(to_clip * instance->xform_cache, push_constant.modelview); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.sdf_render_pipelines[co->sdf_is_lines ? SHADOW_RENDER_SDF_LINES : SHADOW_RENDER_SDF_TRIANGLES]); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->sdf_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, co->sdf_index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + + instance = instance->next; + } + + RD::get_singleton()->draw_list_end(); + + storage->render_target_sdf_process(p_render_target); //done rendering, process it +} + RID RasterizerCanvasRD::occluder_polygon_create() { OccluderPolygon occluder; - occluder.point_count = 0; + occluder.line_point_count = 0; + occluder.sdf_point_count = 0; + occluder.sdf_index_count = 0; occluder.cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; return occluder_polygon_owner.make_rid(occluder); } -void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) { +void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) { OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); ERR_FAIL_COND(!oc); - if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) { + Vector<Vector2> lines; + int lc = p_points.size() * 2; + + lines.resize(lc - (p_closed ? 0 : 2)); + { + Vector2 *w = lines.ptrw(); + const Vector2 *r = p_points.ptr(); + + int max = lc / 2; + if (!p_closed) { + max--; + } + for (int i = 0; i < max; i++) { + Vector2 a = r[i]; + Vector2 b = r[(i + 1) % (lc / 2)]; + w[i * 2 + 0] = a; + w[i * 2 + 1] = b; + } + } + + if (oc->line_point_count != lines.size() && oc->vertex_array.is_valid()) { RD::get_singleton()->free(oc->vertex_array); RD::get_singleton()->free(oc->vertex_buffer); RD::get_singleton()->free(oc->index_array); @@ -1568,12 +1825,14 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con oc->vertex_buffer = RID(); oc->index_array = RID(); oc->index_buffer = RID(); + + oc->line_point_count = lines.size(); } - if (p_lines.size()) { + if (lines.size()) { Vector<uint8_t> geometry; Vector<uint8_t> indices; - int lc = p_lines.size(); + lc = lines.size(); geometry.resize(lc * 6 * sizeof(float)); indices.resize(lc * 3 * sizeof(uint16_t)); @@ -1584,7 +1843,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con uint8_t *iw = indices.ptrw(); uint16_t *iwptr = (uint16_t *)iw; - const Vector2 *lr = p_lines.ptr(); + const Vector2 *lr = lines.ptr(); const int POLY_HEIGHT = 16384; @@ -1638,6 +1897,62 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir); } } + + // sdf + + Vector<int> sdf_indices; + + if (p_closed) { + sdf_indices = Geometry2D::triangulate_polygon(p_points); + oc->sdf_is_lines = false; + } else { + int max = p_points.size(); + sdf_indices.resize(max * 2); + + int *iw = sdf_indices.ptrw(); + for (int i = 0; i < max; i++) { + iw[i * 2 + 0] = i; + iw[i * 2 + 1] = (i + 1) % max; + } + oc->sdf_is_lines = true; + } + + if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) { + RD::get_singleton()->free(oc->sdf_vertex_array); + RD::get_singleton()->free(oc->sdf_vertex_buffer); + RD::get_singleton()->free(oc->sdf_index_array); + RD::get_singleton()->free(oc->sdf_index_buffer); + + oc->sdf_vertex_array = RID(); + oc->sdf_vertex_buffer = RID(); + oc->sdf_index_array = RID(); + oc->sdf_index_buffer = RID(); + + oc->sdf_index_count = sdf_indices.size(); + oc->sdf_point_count = p_points.size(); + + oc->sdf_is_lines = false; + } + + if (sdf_indices.size()) { + if (oc->sdf_vertex_array.is_null()) { + //create from scratch + //vertices + oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(real_t), p_points.to_byte_array()); + oc->sdf_index_buffer = RD::get_singleton()->index_buffer_create(sdf_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, sdf_indices.to_byte_array()); + oc->sdf_index_array = RD::get_singleton()->index_array_create(oc->sdf_index_buffer, 0, sdf_indices.size()); + + Vector<RID> buffer; + buffer.push_back(oc->sdf_vertex_buffer); + oc->sdf_vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), shadow_render.sdf_vertex_format, buffer); + //indices + + } else { + //update existing + RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr()); + RD::get_singleton()->buffer_update(oc->index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr()); + } + } } void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { @@ -1654,6 +1969,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); uses_screen_texture = false; + uses_sdf = false; if (code == String()) { return; //just invalid, but no error @@ -1661,7 +1977,6 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { ShaderCompilerRD::GeneratedCode gen_code; - int light_mode = LIGHT_MODE_NORMAL; int blend_mode = BLEND_MODE_MIX; uses_screen_texture = false; @@ -1674,10 +1989,8 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA); actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED); - actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED); - actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY); - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; actions.uniforms = &uniforms; @@ -1898,6 +2211,7 @@ Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName & RasterizerCanvasRD::ShaderData::ShaderData() { valid = false; uses_screen_texture = false; + uses_sdf = false; } RasterizerCanvasRD::ShaderData::~ShaderData() { @@ -2162,6 +2476,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.renames["LIGHT"] = "light"; actions.renames["SHADOW_MODULATE"] = "shadow_modulate"; + actions.renames["texture_sdf"] = "texture_sdf"; + actions.renames["texture_sdf_normal"] = "texture_sdf_normal"; + actions.renames["sdf_to_screen_uv"] = "sdf_to_screen_uv"; + actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf"; + actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; @@ -2171,6 +2490,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n"; actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n"; actions.custom_samplers["TEXTURE"] = "texture_sampler"; actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler"; @@ -2191,7 +2512,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { //shadow rendering Vector<String> versions; - versions.push_back(String()); //no versions + versions.push_back("\n#define MODE_SHADOW\n"); //shadow + versions.push_back("\n#define MODE_SDF\n"); //sdf shadow_render.shader.initialize(versions); { @@ -2212,16 +2534,34 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); } + { + Vector<RD::AttachmentFormat> attachments; + + RD::AttachmentFormat af_color; + af_color.format = RD::DATA_FORMAT_R8_UNORM; + af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + attachments.push_back(af_color); + + shadow_render.sdf_framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); + } + //pipelines Vector<RD::VertexAttribute> vf; RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32B32_SFLOAT : RD::DATA_FORMAT_R64G64B64_SFLOAT; vd.location = 0; vd.offset = 0; - vd.stride = sizeof(float) * 3; + vd.stride = sizeof(real_t) * 3; vf.push_back(vd); shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf); + vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32_SFLOAT : RD::DATA_FORMAT_R64G64_SFLOAT; + vd.stride = sizeof(real_t) * 2; + + vf.write[0] = vd; + shadow_render.sdf_vertex_format = RD::get_singleton()->vertex_format_create(vf); + shadow_render.shader_version = shadow_render.shader.version_create(); for (int i = 0; i < 3; i++) { @@ -2231,7 +2571,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { ds.enable_depth_write = true; ds.enable_depth_test = true; ds.depth_compare_operator = RD::COMPARE_OP_LESS; - shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SHADOW), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + } + + for (int i = 0; i < 2; i++) { + shadow_render.sdf_render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SDF), shadow_render.sdf_framebuffer_format, shadow_render.sdf_vertex_format, i == 0 ? RD::RENDER_PRIMITIVE_TRIANGLES : RD::RENDER_PRIMITIVE_LINES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); } } @@ -2342,7 +2686,7 @@ bool RasterizerCanvasRD::free(RID p_rid) { light_set_use_shadow(p_rid, false); canvas_light_owner.free(p_rid); } else if (occluder_polygon_owner.owns(p_rid)) { - occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>()); + occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false); occluder_polygon_owner.free(p_rid); } else { return false; @@ -2419,6 +2763,4 @@ RasterizerCanvasRD::~RasterizerCanvasRD() { storage->free(default_canvas_texture); //pipelines don't need freeing, they are all gone after shaders are gone - - RD::get_singleton()->free(state.default_transforms_uniform_set); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h index 3412435367..b09d6578f3 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h @@ -75,7 +75,6 @@ class RasterizerCanvasRD : public RasterizerCanvas { FLAGS_CLIP_RECT_UV = (1 << 9), FLAGS_TRANSPOSE_RECT = (1 << 10), - FLAGS_USING_LIGHT_MASK = (1 << 11), FLAGS_NINEPACH_DRAW_CENTER = (1 << 12), FLAGS_USING_PARTICLES = (1 << 13), @@ -162,12 +161,6 @@ class RasterizerCanvasRD : public RasterizerCanvas { BLEND_MODE_DISABLED, }; - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - bool valid; RID version; PipelineVariants pipeline_variants; @@ -182,7 +175,8 @@ class RasterizerCanvasRD : public RasterizerCanvas { String code; Map<StringName, RID> default_texture_params; - bool uses_screen_texture; + bool uses_screen_texture = false; + bool uses_sdf = false; virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); @@ -269,6 +263,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { bool enabled = false; float z_far; float y_offset; + Transform2D directional_xform; } shadow; }; @@ -284,11 +279,19 @@ class RasterizerCanvasRD : public RasterizerCanvas { struct OccluderPolygon { RS::CanvasOccluderPolygonCullMode cull_mode; - int point_count; + int line_point_count; RID vertex_buffer; RID vertex_array; RID index_buffer; RID index_array; + + int sdf_point_count; + int sdf_index_count; + RID sdf_vertex_buffer; + RID sdf_vertex_array; + RID sdf_index_buffer; + RID sdf_index_array; + bool sdf_is_lines; }; struct LightUniform { @@ -310,12 +313,25 @@ class RasterizerCanvasRD : public RasterizerCanvas { RID_Owner<OccluderPolygon> occluder_polygon_owner; + enum ShadowRenderMode { + SHADOW_RENDER_MODE_SHADOW, + SHADOW_RENDER_MODE_SDF, + }; + + enum { + SHADOW_RENDER_SDF_TRIANGLES, + SHADOW_RENDER_SDF_LINES, + }; + struct { CanvasOcclusionShaderRD shader; RID shader_version; RID render_pipelines[3]; + RID sdf_render_pipelines[2]; RD::VertexFormatID vertex_format; + RD::VertexFormatID sdf_vertex_format; RD::FramebufferFormatID framebuffer_format; + RD::FramebufferFormatID sdf_framebuffer_format; } shadow_render; /***************/ @@ -331,12 +347,19 @@ class RasterizerCanvasRD : public RasterizerCanvas { float screen_transform[16]; float canvas_normal_transform[16]; float canvas_modulate[4]; + float screen_pixel_size[2]; float time; uint32_t use_pixel_snap; - //uint32_t light_count; - //uint32_t pad[3]; + float sdf_to_tex[4]; + float sdf_to_screen[2]; + float screen_to_sdf[2]; + + uint32_t directional_light_count; + float tex_to_sdf; + uint32_t pad1; + uint32_t pad2; }; LightUniform *light_uniforms; @@ -355,6 +378,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { uint32_t max_lights_per_item; double time; + } state; struct PushConstant { @@ -388,6 +412,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { Item *items[MAX_RENDER_ITEMS]; + bool using_directional_lights = false; RID default_canvas_texture; RID default_canvas_group_shader; @@ -408,6 +433,8 @@ class RasterizerCanvasRD : public RasterizerCanvas { _FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4); _FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); + void _update_shadow_atlas(); + public: PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()); void free_polygon(PolygonID p_polygon); @@ -416,12 +443,15 @@ public: void light_set_texture(RID p_rid, RID p_texture); void light_set_use_shadow(RID p_rid, bool p_enable); void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders); + void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders); + + virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders); RID occluder_polygon_create(); - void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines); + void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed); void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode); - void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); + void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used); void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {} diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index d669db1b4b..97c1e7ba70 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -30,8 +30,8 @@ #include "rasterizer_effects_rd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "thirdparty/misc/cubemap_coeffs.h" diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp index 509bd3ee73..5f8cf0ee8c 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp @@ -30,7 +30,7 @@ #include "rasterizer_rd.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" void RasterizerRD::prepare_for_blitting_render_targets() { RD::get_singleton()->prepare_screen_for_drawing(); diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.h b/servers/rendering/rasterizer_rd/rasterizer_rd.h index cdcc6bfd73..59fb8d2049 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_rd.h @@ -32,7 +32,7 @@ #define RASTERIZER_RD_H #include "core/os/os.h" -#include "core/thread_work_pool.h" +#include "core/templates/thread_work_pool.h" #include "servers/rendering/rasterizer.h" #include "servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h" #include "servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h" diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index 35b0591289..313188ba87 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "rasterizer_scene_high_end_rd.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_server_raster.h" @@ -51,6 +51,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { int blend_mode = BLEND_MODE_MIX; int depth_testi = DEPTH_TEST_ENABLED; + int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; int cull = CULL_BACK; uses_point_size = false; @@ -82,6 +83,9 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB); actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); + actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED); actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE); actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS); @@ -154,6 +158,11 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { //blend modes + // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { + blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; + } + RD::PipelineColorBlendState::Attachment blend_attachment; switch (blend_mode) { @@ -199,6 +208,15 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; uses_blend_alpha = true; //force alpha used because of blend } break; + case BLEND_MODE_ALPHA_TO_COVERAGE: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + } } RD::PipelineColorBlendState blend_state_blend; @@ -245,8 +263,17 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { RD::PipelineColorBlendState blend_state; RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; + RD::PipelineMultisampleState multisample_state; if (uses_alpha || uses_blend_alpha) { + // only allow these flags to go through if we have some form of msaa + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + multisample_state.enable_alpha_to_coverage = true; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + multisample_state.enable_alpha_to_coverage = true; + multisample_state.enable_alpha_to_one = true; + } + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { blend_state = blend_state_blend; if (depth_draw == DEPTH_DRAW_OPAQUE) { @@ -286,7 +313,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { } RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); - pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0); + pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); } } } @@ -1211,7 +1238,6 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende } #if 0 if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers); scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers); scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance @@ -1556,7 +1582,6 @@ void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, i } break; #if 0 case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); ERR_CONTINUE(!immediate); @@ -2725,6 +2750,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["POINT_SIZE"] = "gl_PointSize"; actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; + actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; + actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; + actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; + actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; + //builtins actions.renames["TIME"] = "scene_data.time"; @@ -2793,6 +2823,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; + actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; + actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; + actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; + actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h index 566022ae5b..db083a75cc 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h @@ -83,6 +83,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { BLEND_MODE_ADD, BLEND_MODE_SUB, BLEND_MODE_MUL, + BLEND_MODE_ALPHA_TO_COVERAGE }; enum DepthDraw { @@ -110,6 +111,12 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { }; + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE + }; + bool valid; RID version; uint32_t vertex_input_mask; @@ -132,6 +139,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { bool uses_point_size; bool uses_alpha; bool uses_blend_alpha; + bool uses_alpha_clip; bool uses_depth_pre_pass; bool uses_discard; bool uses_roughness; diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index 0cae141138..12fcc6fbb9 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -30,8 +30,8 @@ #include "rasterizer_scene_rd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "rasterizer_rd.h" #include "servers/rendering/rendering_server_raster.h" @@ -351,8 +351,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co RD::TextureFormat tf_probe_average = tf_probes; tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed - tf_probe_average.type = RD::TEXTURE_TYPE_2D_ARRAY; - tf_probe_average.array_layers = 1; + tf_probe_average.type = RD::TEXTURE_TYPE_2D; sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); @@ -1471,7 +1470,9 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } if (giprobes_changed) { - RD::get_singleton()->free(rb->gi_uniform_set); + if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { + RD::get_singleton()->free(rb->gi_uniform_set); + } rb->gi_uniform_set = RID(); if (rb->volumetric_fog) { if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { @@ -8216,7 +8217,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { RD::Uniform u; u.type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); uniforms.push_back(u); } { diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index 2ad712a9d3..3d5310bb7e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -31,8 +31,8 @@ #ifndef RASTERIZER_SCENE_RD_H #define RASTERIZER_SCENE_RD_H -#include "core/local_vector.h" -#include "core/rid_owner.h" +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" #include "servers/rendering/rasterizer.h" #include "servers/rendering/rasterizer_rd/light_cluster_builder.h" #include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 10c9293d67..444ef9c49a 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -30,9 +30,9 @@ #include "rasterizer_storage_rd.h" -#include "core/engine.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "core/io/resource_loader.h" -#include "core/project_settings.h" #include "rasterizer_rd.h" #include "servers/rendering/shader_language.h" @@ -1265,7 +1265,7 @@ void RasterizerStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture 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) { +bool RasterizerStorageRD::canvas_texture_get_uniform_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); @@ -5549,7 +5549,6 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t } RID shared_tex; { - RD::TextureView tv; tv.format_override = RD::DATA_FORMAT_R8_UINT; shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture); @@ -6030,6 +6029,8 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { rt->backbuffer_uniform_set = RID(); //chain deleted } + _render_target_clear_sdf(rt); + rt->framebuffer = RID(); rt->color = RID(); } @@ -6300,6 +6301,275 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { rt->clear_requested = false; } +void RasterizerStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) { + return; + } + + rt->sdf_oversize = p_size; + rt->sdf_scale = p_scale; + + _render_target_clear_sdf(rt); +} + +Rect2i RasterizerStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) const { + Size2i margin; + int scale; + switch (rt->sdf_oversize) { + case RS::VIEWPORT_SDF_OVERSIZE_100_PERCENT: { + scale = 100; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT: { + scale = 120; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_150_PERCENT: { + scale = 150; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_200_PERCENT: { + scale = 200; + } break; + default: { + } + } + + margin = (rt->size * scale / 100) - rt->size; + + Rect2i r(Vector2i(), rt->size); + r.position -= margin; + r.size += margin * 2; + + return r; +} + +Rect2i RasterizerStorageRD::render_target_get_sdf_rect(RID p_render_target) const { + const RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Rect2i()); + + return _render_target_get_sdf_rect(rt); +} + +RID RasterizerStorageRD::render_target_get_sdf_texture(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + if (rt->sdf_buffer_read.is_null()) { + // no texture, create a dummy one for the 2D uniform set + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + + Vector<uint8_t> pv; + pv.resize(16 * 4); + zeromem(pv.ptrw(), 16 * 4); + Vector<Vector<uint8_t>> vpv; + + rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + return rt->sdf_buffer_read; +} + +void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { + ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_valid()); + if (rt->sdf_buffer_read.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_read); + rt->sdf_buffer_read = RID(); + } + + Size2i size = _render_target_get_sdf_rect(rt).size; + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8_UNORM; + tformat.width = size.width; + tformat.height = size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + + rt->sdf_buffer_write = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + Vector<RID> write_fb; + write_fb.push_back(rt->sdf_buffer_write); + rt->sdf_buffer_write_fb = RD::get_singleton()->framebuffer_create(write_fb); + } + + int scale; + switch (rt->sdf_scale) { + case RS::VIEWPORT_SDF_SCALE_100_PERCENT: { + scale = 100; + } break; + case RS::VIEWPORT_SDF_SCALE_50_PERCENT: { + scale = 50; + } break; + case RS::VIEWPORT_SDF_SCALE_25_PERCENT: { + scale = 25; + } break; + default: { + scale = 100; + } break; + } + + rt->process_size = size * scale / 100; + rt->process_size.x = MAX(rt->process_size.x, 1); + rt->process_size.y = MAX(rt->process_size.y, 1); + + tformat.format = RD::DATA_FORMAT_R16G16_UINT; + tformat.width = rt->process_size.width; + tformat.height = rt->process_size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + + rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + tformat.format = RD::DATA_FORMAT_R16_UNORM; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + + rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(rt->sdf_buffer_write); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(rt->sdf_buffer_read); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 3; + u.ids.push_back(rt->sdf_buffer_process[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 4; + u.ids.push_back(rt->sdf_buffer_process[1]); + uniforms.push_back(u); + } + + rt->sdf_buffer_process_uniform_sets[0] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0); + SWAP(uniforms.write[2].ids.write[0], uniforms.write[3].ids.write[0]); + rt->sdf_buffer_process_uniform_sets[1] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0); + } +} + +void RasterizerStorageRD::_render_target_clear_sdf(RenderTarget *rt) { + if (rt->sdf_buffer_read.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_read); + rt->sdf_buffer_read = RID(); + } + if (rt->sdf_buffer_write_fb.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_write); + RD::get_singleton()->free(rt->sdf_buffer_process[0]); + RD::get_singleton()->free(rt->sdf_buffer_process[1]); + rt->sdf_buffer_write = RID(); + rt->sdf_buffer_write_fb = RID(); + rt->sdf_buffer_process[0] = RID(); + rt->sdf_buffer_process[1] = RID(); + rt->sdf_buffer_process_uniform_sets[0] = RID(); + rt->sdf_buffer_process_uniform_sets[1] = RID(); + } +} + +RID RasterizerStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->sdf_buffer_write_fb.is_null()) { + _render_target_allocate_sdf(rt); + } + + return rt->sdf_buffer_write_fb; +} +void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null()); + + RenderTargetSDF::PushConstant push_constant; + + Rect2i r = _render_target_get_sdf_rect(rt); + + push_constant.size[0] = r.size.width; + push_constant.size[1] = r.size.height; + push_constant.stride = 0; + push_constant.shift = 0; + push_constant.base_size[0] = r.size.width; + push_constant.base_size[1] = r.size.height; + + bool shrink = false; + + switch (rt->sdf_scale) { + case RS::VIEWPORT_SDF_SCALE_50_PERCENT: { + push_constant.size[0] >>= 1; + push_constant.size[1] >>= 1; + push_constant.shift = 1; + shrink = true; + } break; + case RS::VIEWPORT_SDF_SCALE_25_PERCENT: { + push_constant.size[0] >>= 2; + push_constant.size[1] >>= 2; + push_constant.shift = 2; + shrink = true; + } break; + default: { + }; + } + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + /* Load */ + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_LOAD_SHRINK : RenderTargetSDF::SHADER_LOAD]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[1], 0); //fill [0] + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + + /* Process */ + + int stride = nearest_power_of_2_templated(MAX(push_constant.size[0], push_constant.size[1]) / 2); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[RenderTargetSDF::SHADER_PROCESS]); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + bool swap = false; + + //jumpflood + while (stride > 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); + push_constant.stride = stride; + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + stride /= 2; + swap = !swap; + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + + /* Store */ + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_STORE_SHRINK : RenderTargetSDF::SHADER_STORE]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + + RD::get_singleton()->compute_list_end(); +} + void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -7756,6 +8026,34 @@ RasterizerStorageRD::RasterizerStorageRD() { } } + { //create default cubemap white array + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.array_layers = 6; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + tformat.type = RD::TEXTURE_TYPE_CUBE; + + Vector<uint8_t> pv; + pv.resize(16 * 4); + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 255); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<Vector<uint8_t>> vpv; + for (int i = 0; i < 6; i++) { + vpv.push_back(pv); + } + default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + } + { //create default 3D RD::TextureFormat tformat; @@ -8128,6 +8426,24 @@ RasterizerStorageRD::RasterizerStorageRD() { particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i)); } } + + { + Vector<String> sdf_modes; + sdf_modes.push_back("\n#define MODE_LOAD\n"); + sdf_modes.push_back("\n#define MODE_LOAD_SHRINK\n"); + sdf_modes.push_back("\n#define MODE_PROCESS\n"); + sdf_modes.push_back("\n#define MODE_PROCESS_OPTIMIZED\n"); + sdf_modes.push_back("\n#define MODE_STORE\n"); + sdf_modes.push_back("\n#define MODE_STORE_SHRINK\n"); + + rt_sdf.shader.initialize(sdf_modes); + + rt_sdf.shader_version = rt_sdf.shader.version_create(); + + for (int i = 0; i < RenderTargetSDF::SHADER_MAX; i++) { + rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i)); + } + } } RasterizerStorageRD::~RasterizerStorageRD() { diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 321bff9fdd..4a708fc94f 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -31,10 +31,11 @@ #ifndef RASTERIZER_STORAGE_RD_H #define RASTERIZER_STORAGE_RD_H -#include "core/rid_owner.h" +#include "core/templates/rid_owner.h" #include "servers/rendering/rasterizer.h" #include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h" #include "servers/rendering/rasterizer_rd/shader_compiler_rd.h" +#include "servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h" @@ -155,6 +156,7 @@ public: DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER, DEFAULT_RD_TEXTURE_CUBEMAP_BLACK, DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK, + DEFAULT_RD_TEXTURE_CUBEMAP_WHITE, DEFAULT_RD_TEXTURE_3D_WHITE, DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE, DEFAULT_RD_TEXTURE_2D_UINT, @@ -1002,6 +1004,15 @@ private: RID framebuffer_uniform_set; RID backbuffer_uniform_set; + RID sdf_buffer_write; + RID sdf_buffer_write_fb; + RID sdf_buffer_process[2]; + RID sdf_buffer_read; + RID sdf_buffer_process_uniform_sets[2]; + RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT; + RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT; + Size2i process_size; + //texture generated for this owner (nor RD). RID texture; bool was_used; @@ -1011,11 +1022,38 @@ private: Color clear_color; }; - RID_Owner<RenderTarget> render_target_owner; + mutable RID_Owner<RenderTarget> render_target_owner; void _clear_render_target(RenderTarget *rt); void _update_render_target(RenderTarget *rt); void _create_render_target_backbuffer(RenderTarget *rt); + void _render_target_allocate_sdf(RenderTarget *rt); + void _render_target_clear_sdf(RenderTarget *rt); + Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const; + + struct RenderTargetSDF { + enum { + SHADER_LOAD, + SHADER_LOAD_SHRINK, + SHADER_PROCESS, + SHADER_PROCESS_OPTIMIZED, + SHADER_STORE, + SHADER_STORE_SHRINK, + SHADER_MAX + }; + + struct PushConstant { + int32_t size[2]; + int32_t stride; + int32_t shift; + int32_t base_size[2]; + int32_t pad[2]; + }; + + CanvasSdfShaderRD shader; + RID shader_version; + RID pipelines[SHADER_MAX]; + } rt_sdf; /* GLOBAL SHADER VARIABLES */ @@ -1185,7 +1223,7 @@ public: virtual void canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter); virtual void canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat); - bool 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); + bool canvas_texture_get_uniform_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); /* SHADER API */ @@ -1929,6 +1967,12 @@ public: virtual void render_target_disable_clear_request(RID p_render_target); virtual void render_target_do_clear_request(RID p_render_target); + virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale); + RID render_target_get_sdf_texture(RID p_render_target); + RID render_target_get_sdf_framebuffer(RID p_render_target); + void render_target_sdf_process(RID p_render_target); + virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const; + Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); RID render_target_get_rd_texture(RID p_render_target); diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h index cf15e79586..6a72dbc77c 100644 --- a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h +++ b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h @@ -31,7 +31,7 @@ #ifndef RENDER_PIPELINE_CACHE_RD_H #define RENDER_PIPELINE_CACHE_RD_H -#include "core/spin_lock.h" +#include "core/os/spin_lock.h" #include "servers/rendering/rendering_device.h" class RenderPipelineVertexFormatCacheRD { diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp index 0a0c343e57..df5513435a 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp @@ -30,8 +30,8 @@ #include "shader_compiler_rd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "rasterizer_storage_rd.h" #include "servers/rendering_server.h" @@ -671,7 +671,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } /* for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) { - if (SL::is_sampler_type(E->get().type)) { continue; } @@ -1073,6 +1072,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } else if (onode->op == SL::OP_CONSTRUCT) { code += String(vnode->name); } else { + if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) { + *p_actions.usage_flag_pointers[vnode->name] = true; + used_flag_pointers.insert(vnode->name); + } + if (internal_functions.has(vnode->name)) { code += vnode->name; is_texture_func = texture_functions.has(vnode->name); diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/rasterizer_rd/shader_compiler_rd.h index 565520ec65..694f8fff91 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.h @@ -31,7 +31,7 @@ #ifndef SHADER_COMPILER_RD_H #define SHADER_COMPILER_RD_H -#include "core/pair.h" +#include "core/templates/pair.h" #include "servers/rendering/shader_language.h" #include "servers/rendering/shader_types.h" #include "servers/rendering_server.h" diff --git a/servers/rendering/rasterizer_rd/shader_rd.cpp b/servers/rendering/rasterizer_rd/shader_rd.cpp index 8c57651263..865a1e1bbe 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.cpp +++ b/servers/rendering/rasterizer_rd/shader_rd.cpp @@ -30,7 +30,7 @@ #include "shader_rd.h" -#include "core/string_builder.h" +#include "core/string/string_builder.h" #include "rasterizer_rd.h" #include "servers/rendering/rendering_device.h" diff --git a/servers/rendering/rasterizer_rd/shader_rd.h b/servers/rendering/rasterizer_rd/shader_rd.h index d9bb068ba6..0c379db6f2 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.h +++ b/servers/rendering/rasterizer_rd/shader_rd.h @@ -31,11 +31,11 @@ #ifndef SHADER_RD_H #define SHADER_RD_H -#include "core/hash_map.h" -#include "core/map.h" #include "core/os/mutex.h" -#include "core/rid_owner.h" -#include "core/variant.h" +#include "core/templates/hash_map.h" +#include "core/templates/map.h" +#include "core/templates/rid_owner.h" +#include "core/variant/variant.h" #include <stdio.h> /** diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index 9d531d63ad..4cddf0f685 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -5,6 +5,7 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("canvas.glsl") env.RD_GLSL("canvas_occlusion.glsl") + env.RD_GLSL("canvas_sdf.glsl") env.RD_GLSL("copy.glsl") env.RD_GLSL("copy_to_fb.glsl") env.RD_GLSL("cubemap_roughness.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl index b382c0d85f..51d7193a03 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl @@ -233,6 +233,30 @@ MATERIAL_UNIFORMS } material; #endif +vec2 screen_uv_to_sdf(vec2 p_uv) { + return canvas_data.screen_to_sdf * p_uv; +} + +float texture_sdf(vec2 p_sdf) { + vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; + float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r; + d = d * SDF_MAX_LENGTH - 1.0; + return d * canvas_data.tex_to_sdf; +} + +vec2 texture_sdf_normal(vec2 p_sdf) { + vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; + + const float EPSILON = 0.001; + return normalize(vec2( + texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r, + texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r)); +} + +vec2 sdf_to_screen_uv(vec2 p_sdf) { + return p_sdf * canvas_data.sdf_to_screen; +} + /* clang-format off */ FRAGMENT_SHADER_GLOBALS /* clang-format on */ @@ -249,7 +273,7 @@ vec4 light_compute( inout vec4 shadow_modulate, vec2 screen_uv, vec2 uv, - vec4 color) { + vec4 color, bool is_directional) { vec4 light = vec4(0.0); /* clang-format off */ LIGHT_SHADER_CODE @@ -302,6 +326,99 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo #endif +#ifdef USE_LIGHTING + +vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) { + float cNdotL = max(0.0, dot(normal, light_vec)); + + if (specular_shininess_used) { + //blinn + vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough + vec3 half_vec = normalize(view + light_vec); + + float cNdotV = max(dot(normal, view), 0.0); + float cNdotH = max(dot(normal, half_vec), 0.0); + float cVdotH = max(dot(view, half_vec), 0.0); + float cLdotH = max(dot(light_vec, half_vec), 0.0); + float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + + return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL; + } else { + return light_color * base_color * cNdotL; + } +} + +//float distance = length(shadow_pos); +vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv +#ifdef LIGHT_SHADER_CODE_USED + , + vec3 shadow_modulate +#endif +) { + float shadow; + uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; + + if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { + shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; + } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { + vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow /= 5.0; + } else { //PCF13 + vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x; + shadow /= 13.0; + } + + vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); +#ifdef LIGHT_SHADER_CODE_USED + shadow_color *= shadow_modulate; +#endif + + shadow_color.a *= light_color.a; //respect light alpha + + return mix(light_color, shadow_color, shadow); +} + +void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { + uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; + + switch (blend_mode) { + case LIGHT_FLAGS_BLEND_MODE_ADD: { + color.rgb += light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_SUB: { + color.rgb -= light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_MIX: { + color.rgb = mix(color.rgb, light_color.rgb, light_color.a); + } break; + } +} + +#endif + void main() { vec4 color = color_interp; vec2 uv = uv_interp; @@ -332,6 +449,7 @@ void main() { color *= texture(sampler2D(color_texture, texture_sampler), uv); uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights + bool using_light = light_count > 0 || canvas_data.directional_light_count > 0; vec3 normal; @@ -341,7 +459,7 @@ void main() { bool normal_used = false; #endif - if (normal_used || (light_count > 0 && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { + if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; @@ -358,7 +476,7 @@ void main() { bool specular_shininess_used = false; #endif - if (specular_shininess_used || (light_count > 0 && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { + if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv); specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess); specular_shininess_used = true; @@ -401,13 +519,57 @@ FRAGMENT_SHADER_CODE normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz); } - vec4 base_color = color; + vec3 base_color = color.rgb; if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) { color = vec4(0.0); //invisible by default due to using light mask } +#ifdef MODE_LIGHT_ONLY + color = vec4(0.0); +#else color *= canvas_data.canvas_modulation; -#ifdef USE_LIGHTING +#endif + +#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED) + + // Directional Lights + + for (uint i = 0; i < canvas_data.directional_light_count; i++) { + uint light_base = i; + + vec2 direction = light_array.data[light_base].position; + vec4 light_color = light_array.data[light_base].color; + +#ifdef LIGHT_SHADER_CODE_USED + + vec4 shadow_modulate = vec4(1.0); + light_color = light_compute(light_vertex, direction, normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, true); +#else + + if (normal_used) { + vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height)); + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); + } +#endif + + if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { + vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + + vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0); + + light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_SHADER_CODE_USED + , + shadow_modulate +#endif + ); + } + + light_blend_compute(light_base, light_color, color.rgb); + } + + // Positional Lights + for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) { if (i >= light_count) { break; @@ -440,7 +602,7 @@ FRAGMENT_SHADER_CODE vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height); light_color.rgb *= light_base_color.rgb; - light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv); + light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, false); #else light_color.rgb *= light_base_color.rgb * light_base_color.a; @@ -451,24 +613,7 @@ FRAGMENT_SHADER_CODE vec3 light_vec = normalize(light_pos - pos); float cNdotL = max(0.0, dot(normal, light_vec)); - if (specular_shininess_used) { - //blinn - vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough - vec3 half_vec = normalize(view + light_vec); - - float cNdotV = max(dot(normal, view), 0.0); - float cNdotH = max(dot(normal, half_vec), 0.0); - float cVdotH = max(dot(view, half_vec), 0.0); - float cLdotH = max(dot(light_vec, half_vec), 0.0); - float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess); - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); - - light_color.rgb = specular_shininess.rgb * light_base_color.rgb * s + light_color.rgb * cNdotL; - } else { - light_color.rgb *= cNdotL; - } + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); } #endif if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { @@ -506,69 +651,17 @@ FRAGMENT_SHADER_CODE distance *= light_array.data[light_base].shadow_zfar_inv; //float distance = length(shadow_pos); - float shadow; - uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; - vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0); - if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { - shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; - } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { - vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); - shadow = 0.0; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; - shadow /= 5.0; - } else { //PCF13 - vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); - shadow = 0.0; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x; - shadow /= 13.0; - } - - vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); + light_color = light_shadow_compute(light_base, light_color, shadow_uv #ifdef LIGHT_SHADER_CODE_USED - shadow_color *= shadow_modulate; + , + shadow_modulate #endif - - shadow_color.a *= light_color.a; //respect light alpha - - light_color = mix(light_color, shadow_color, shadow); - //light_color = mix(light_color, shadow_color, shadow); + ); } - uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; - - switch (blend_mode) { - case LIGHT_FLAGS_BLEND_MODE_ADD: { - color.rgb += light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_SUB: { - color.rgb -= light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_MIX: { - color.rgb = mix(color.rgb, light_color.rgb, light_color.a); - } break; - case LIGHT_FLAGS_BLEND_MODE_MASK: { - light_color.a *= base_color.a; - color.rgb = mix(color.rgb, light_color.rgb, light_color.a); - } break; - } + light_blend_compute(light_base, light_color, color.rgb); } #endif diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl index 421282cd4d..5c25235c58 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl @@ -2,6 +2,8 @@ #version 450 +VERSION_DEFINES + layout(location = 0) in highp vec3 vertex; layout(push_constant, binding = 0, std430) uniform Constants { @@ -13,12 +15,16 @@ layout(push_constant, binding = 0, std430) uniform Constants { } constants; +#ifdef MODE_SHADOW layout(location = 0) out highp float depth; +#endif void main() { highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - depth = dot(constants.direction, vtx.xy); +#ifdef MODE_SHADOW + depth = dot(constants.direction, vtx.xy); +#endif gl_Position = constants.projection * vtx; } @@ -26,6 +32,8 @@ void main() { #version 450 +VERSION_DEFINES + layout(push_constant, binding = 0, std430) uniform Constants { mat4 projection; mat2x4 modelview; @@ -35,9 +43,17 @@ layout(push_constant, binding = 0, std430) uniform Constants { } constants; +#ifdef MODE_SHADOW layout(location = 0) in highp float depth; layout(location = 0) out highp float distance_buf; +#else +layout(location = 0) out highp float sdf_buf; +#endif void main() { +#ifdef MODE_SHADOW distance_buf = depth / constants.z_far; +#else + sdf_buf = 1.0; +#endif } diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl new file mode 100644 index 0000000000..302ad03b41 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl @@ -0,0 +1,135 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels; +layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf; + +layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process; +layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process; + +layout(push_constant, binding = 0, std430) uniform Params { + ivec2 size; + int stride; + int shift; + ivec2 base_size; + uvec2 pad; +} +params; + +#define SDF_MAX_LENGTH 16384.0 + +void main() { + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pos, params.size))) { //too large, do nothing + return; + } + +#ifdef MODE_LOAD + + bool solid = imageLoad(src_pixels, pos).r > 0.5; + imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0)); +#endif + +#ifdef MODE_LOAD_SHRINK + + int s = 1 << params.shift; + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = ivec2(32767); + float d = 1e20; + for (int i = 0; i < s; i++) { + for (int j = 0; j < s; j++) { + ivec2 src_pos = base + ivec2(i, j); + if (any(greaterThanEqual(src_pos, params.base_size))) { + continue; + } + bool solid = imageLoad(src_pixels, src_pos).r > 0.5; + if (solid) { + float dist = length(vec2(src_pos - center)); + if (dist < d) { + d = dist; + rel = src_pos; + } + } + } + } + + imageStore(dst_process, pos, ivec4(rel, 0, 0)); +#endif + +#ifdef MODE_PROCESS + + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = imageLoad(src_process, pos).xy; + + if (center != rel) { + //only process if it does not point to itself + const int ofs_table_size = 8; + const ivec2 ofs_table[ofs_table_size] = ivec2[]( + ivec2(-1, -1), + ivec2(0, -1), + ivec2(+1, -1), + + ivec2(-1, 0), + ivec2(+1, 0), + + ivec2(-1, +1), + ivec2(0, +1), + ivec2(+1, +1)); + + float dist = length(vec2(rel - center)); + for (int i = 0; i < ofs_table_size; i++) { + ivec2 src_pos = pos + ofs_table[i] * params.stride; + if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, params.size))) { + continue; + } + ivec2 src_rel = imageLoad(src_process, src_pos).xy; + float src_dist = length(vec2(src_rel - center)); + if (src_dist < dist) { + dist = src_dist; + rel = src_rel; + } + } + } + + imageStore(dst_process, pos, ivec4(rel, 0, 0)); +#endif + +#ifdef MODE_STORE + + ivec2 rel = imageLoad(src_process, pos).xy; + float d = length(vec2(rel - pos)); + if (d > 0.01) { + d += 1.0; //make it signed + } + d /= SDF_MAX_LENGTH; + d = clamp(d, 0.0, 1.0); + imageStore(dst_sdf, pos, vec4(d)); + +#endif + +#ifdef MODE_STORE_SHRINK + + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = imageLoad(src_process, pos).xy; + float d = length(vec2(rel - center)); + + if (d > 0.01) { + d += 1.0; //make it signed + } + d /= SDF_MAX_LENGTH; + d = clamp(d, 0.0, 1.0); + imageStore(dst_sdf, pos, vec4(d)); + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl index 1a226a87d3..cf7678ea31 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -3,6 +3,8 @@ #define M_PI 3.14159265359 +#define SDF_MAX_LENGTH 16384.0 + #define FLAGS_INSTANCING_STRIDE_MASK 0xF #define FLAGS_INSTANCING_ENABLED (1 << 4) #define FLAGS_INSTANCING_HAS_COLORS (1 << 5) @@ -24,6 +26,19 @@ #define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26) #define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + // Push Constant layout(push_constant, binding = 0, std430) uniform DrawData { @@ -68,7 +83,14 @@ layout(set = 0, binding = 1, std140) uniform CanvasData { float time; bool use_pixel_snap; - //uint light_count; + vec4 sdf_to_tex; + vec2 screen_to_sdf; + vec2 sdf_to_screen; + + uint directional_light_count; + float tex_to_sdf; + uint pad1; + uint pad2; } canvas_data; @@ -112,10 +134,11 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture; layout(set = 0, binding = 5) uniform sampler shadow_sampler; layout(set = 0, binding = 6) uniform texture2D screen_texture; +layout(set = 0, binding = 7) uniform texture2D sdf_texture; -layout(set = 0, binding = 7) uniform sampler material_samplers[12]; +layout(set = 0, binding = 8) uniform sampler material_samplers[12]; -layout(set = 0, binding = 8, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalVariableData { vec4 data[]; } global_variables; diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 455a3d4a3a..285698f060 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -361,6 +361,65 @@ layout(location = 0) out vec4 frag_color; #endif // RENDER DEPTH +#ifdef ALPHA_HASH_USED + +float hash_2d(vec2 p) { + return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * + (0.1 + abs(sin(13.0 * p.y + p.x)))); +} + +float hash_3d(vec3 p) { + return hash_2d(vec2(hash_2d(p.xy), p.z)); +} + +float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { + vec3 dx = dFdx(pos); + vec3 dy = dFdx(pos); + float delta_max_sqr = max(length(dx), length(dy)); + float pix_scale = 1.0 / (hash_scale * delta_max_sqr); + + vec2 pix_scales = + vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); + + vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), + hash_3d(floor(pix_scales.y * pos.xyz))); + + float lerp_factor = fract(log2(pix_scale)); + + float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; + + float min_lerp = min(lerp_factor, 1.0 - lerp_factor); + + vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), + (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), + 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / + (2.0 * min_lerp * (1.0 - min_lerp)))); + + float alpha_hash_threshold = + (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; + + return clamp(alpha_hash_threshold, 0.0, 1.0); +} + +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + +float calc_mip_level(vec2 texture_coord) { + vec2 dx = dFdx(texture_coord); + vec2 dy = dFdy(texture_coord); + float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); + return max(0.0, 0.5 * log2(delta_max_sqr)); +} + +float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { + input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number + input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; + return clamp(input_alpha, 0.0, 1.0); +} + +#endif // ALPHA_ANTIALIASING_USED + // This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. // We're dividing this factor off because the overall term we'll end up looks like // (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): @@ -809,7 +868,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v inout float alpha, #endif inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = lights.data[idx].position - vertex; float light_length = length(light_rel_vec); float normalized_distance = light_length * lights.data[idx].inv_radius; @@ -1099,7 +1157,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #endif inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = lights.data[idx].position - vertex; float light_length = length(light_rel_vec); float normalized_distance = light_length * lights.data[idx].inv_radius; @@ -1709,10 +1766,6 @@ void main() { float alpha = 1.0; -#if defined(ALPHA_SCISSOR_USED) - float alpha_scissor = 0.5; -#endif - #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 binormal = normalize(binormal_interp); vec3 tangent = normalize(tangent_interp); @@ -1749,6 +1802,19 @@ void main() { float sss_strength = 0.0; +#ifdef ALPHA_SCISSOR_USED + float alpha_scissor_threshold = 1.0; +#endif // ALPHA_SCISSOR_USED + +#ifdef ALPHA_HASH_USED + float alpha_hash_scale = 1.0; +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + float alpha_antialiasing_edge = 0.0; + vec2 alpha_texture_coordinate = vec2(0.0, 0.0); +#endif // ALPHA_ANTIALIASING_EDGE_USED + { /* clang-format off */ @@ -1757,7 +1823,7 @@ FRAGMENT_SHADER_CODE /* clang-format on */ } -#if defined(LIGHT_TRANSMITTANCE_USED) +#ifdef LIGHT_TRANSMITTANCE_USED #ifdef SSS_MODE_SKIN transmittance_color.a = sss_strength; #else @@ -1765,25 +1831,43 @@ FRAGMENT_SHADER_CODE #endif #endif -#if !defined(USE_SHADOW_TO_OPACITY) +#ifndef USE_SHADOW_TO_OPACITY -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { +#ifdef ALPHA_SCISSOR_USED + if (alpha < alpha_scissor_threshold) { discard; } #endif // ALPHA_SCISSOR_USED -#ifdef USE_OPAQUE_PREPASS +// alpha hash can be used in unison with alpha antialiasing +#ifdef ALPHA_HASH_USED + if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) { + discard; + } +#endif // ALPHA_HASH_USED + +// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) + alpha = 1.0; +#endif + +#ifdef ALPHA_ANTIALIASING_EDGE_USED +// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather +#ifdef ALPHA_SCISSOR_USED + alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0); +#endif + alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge); +#endif // ALPHA_ANTIALIASING_EDGE_USED +#ifdef USE_OPAQUE_PREPASS if (alpha < opaque_prepass_threshold) { discard; } - #endif // USE_OPAQUE_PREPASS #endif // !USE_SHADOW_TO_OPACITY -#if defined(NORMALMAP_USED) +#ifdef NORMALMAP_USED normalmap.xy = normalmap.xy * 2.0 - 1.0; normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. @@ -1792,7 +1876,7 @@ FRAGMENT_SHADER_CODE #endif -#if defined(LIGHT_ANISOTROPY_USED) +#ifdef LIGHT_ANISOTROPY_USED if (anisotropy > 0.01) { //rotation matrix |