diff options
Diffstat (limited to 'servers/visual/rasterizer')
-rw-r--r-- | servers/visual/rasterizer/rasterizer.h | 43 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_canvas_rd.cpp | 621 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_canvas_rd.h | 142 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_storage_rd.h | 9 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/SCsub | 2 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/canvas.glsl | 141 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/canvas_occlusion.glsl | 38 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/canvas_occlusion_fix.glsl | 56 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl | 48 |
9 files changed, 973 insertions, 127 deletions
diff --git a/servers/visual/rasterizer/rasterizer.h b/servers/visual/rasterizer/rasterizer.h index 853d02f7c3..88520a6a79 100644 --- a/servers/visual/rasterizer/rasterizer.h +++ b/servers/visual/rasterizer/rasterizer.h @@ -562,15 +562,6 @@ public: virtual void render_target_disable_clear_request(RID p_render_target) = 0; virtual void render_target_do_clear_request(RID p_render_target) = 0; - /* CANVAS SHADOW */ - - virtual RID canvas_light_shadow_buffer_create(int p_width) = 0; - - /* LIGHT SHADOW MAPPING */ - - virtual RID canvas_light_occluder_create() = 0; - virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) = 0; - virtual VS::InstanceType get_base_type(RID p_rid) const = 0; virtual bool free(RID p_rid) = 0; @@ -625,21 +616,21 @@ public: RID texture; Vector2 texture_offset; RID canvas; - RID shadow_buffer; + bool use_shadow; int shadow_buffer_size; float shadow_gradient_length; VS::CanvasLightShadowFilter shadow_filter; Color shadow_color; float shadow_smooth; - void *texture_cache; // implementation dependent + //void *texture_cache; // implementation dependent Rect2 rect_cache; Transform2D xform_cache; float radius_cache; //used for shadow far plane - CameraMatrix shadow_matrix_cache; + //CameraMatrix shadow_matrix_cache; Transform2D light_shader_xform; - Vector2 light_shader_pos; + //Vector2 light_shader_pos; Light *shadows_next_ptr; Light *filter_next_ptr; @@ -648,6 +639,8 @@ public: RID light_internal; + int32_t render_index_cache; + Light() { enabled = true; color = Color(1, 1, 1); @@ -662,21 +655,19 @@ public: energy = 1.0; item_shadow_mask = -1; mode = VS::CANVAS_LIGHT_MODE_ADD; - texture_cache = NULL; + // texture_cache = NULL; next_ptr = NULL; mask_next_ptr = NULL; filter_next_ptr = NULL; + use_shadow = false; shadow_buffer_size = 2048; shadow_gradient_length = 0; shadow_filter = VS::CANVAS_LIGHT_FILTER_NONE; shadow_smooth = 0.0; + render_index_cache = -1; } }; - virtual RID light_internal_create() = 0; - virtual void light_internal_update(RID p_rid, Light *p_light) = 0; - virtual void light_internal_free(RID p_rid) = 0; - typedef uint64_t TextureBindingID; virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) = 0; @@ -957,7 +948,7 @@ public: case Item::Command::TYPE_PRIMITIVE: { const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - for (int j = 0; j < primitive->point_count; j++) { + for (uint32_t j = 0; j < primitive->point_count; j++) { if (j == 0) { r.position = primitive->points[0]; } else { @@ -1085,7 +1076,7 @@ public: c = n; } { - uint32_t cbc = MIN((current_block + 1), blocks.size()); + uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size()); CommandBlock *blockptr = blocks.ptrw(); for (uint32_t i = 0; i < cbc; i++) { blockptr[i].usage = 0; @@ -1139,7 +1130,7 @@ public: bool enabled; RID canvas; RID polygon; - RID polygon_buffer; + RID occluder; Rect2 aabb_cache; Transform2D xform; Transform2D xform_cache; @@ -1156,12 +1147,18 @@ public: } }; - virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) = 0; + virtual RID light_create() = 0; + virtual void light_set_texture(RID p_rid, RID p_texture) = 0; + virtual void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) = 0; + virtual void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0; - virtual void reset_canvas() = 0; + virtual RID occluder_polygon_create() = 0; + virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const PoolVector<Vector2> &p_lines) = 0; + virtual void occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) = 0; virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; + virtual bool free(RID p_rid) = 0; virtual void update() = 0; RasterizerCanvas() { singleton = this; } diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp index d72be70677..838e26ac73 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp @@ -63,6 +63,14 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, p_mat4[15] = 1; } +void RasterizerCanvasRD::_update_specular_shininess(const Color &p_transform, uint32_t *r_ss) { + + *r_ss = uint32_t(CLAMP(p_transform.a * 255.0, 0, 255)) << 24; + *r_ss |= uint32_t(CLAMP(p_transform.b * 255.0, 0, 255)) << 16; + *r_ss |= uint32_t(CLAMP(p_transform.g * 255.0, 0, 255)) << 8; + *r_ss |= uint32_t(CLAMP(p_transform.r * 255.0, 0, 255)); +} + RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { Vector<RD::Uniform> uniform_set; @@ -472,12 +480,19 @@ void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { polygon_buffers.polygons.erase(p_polygon); } -Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list) { +Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list, uint32_t &flags) { TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding); ERR_FAIL_COND_V(!texture_binding_ptr, Size2i()); TextureBinding *texture_binding = *texture_binding_ptr; + if (texture_binding->key.normalmap.is_valid()) { + flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; + } + if (texture_binding->key.specular.is_valid()) { + flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + } + if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) { //texture may have changed (erased or replaced, see if we can fix) texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh); @@ -493,12 +508,15 @@ Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD: } //////////////////// -void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip) { +void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights) { //create an empty push constant PushConstant push_constant; Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; _update_transform_2d_to_mat2x3(base_transform, push_constant.world); + + Color base_color = p_item->final_modulate; + for (int i = 0; i < 4; i++) { push_constant.modulation[i] = 0; push_constant.ninepatch_margins[i] = 0; @@ -506,7 +524,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.dst_rect[i] = 0; } push_constant.flags = 0; - push_constant.specular_shininess = 0xFFFFFFFF; push_constant.color_texture_pixel_size[0] = 0; push_constant.color_texture_pixel_size[1] = 0; @@ -514,6 +531,37 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.pad[2] = 0; push_constant.pad[3] = 0; + push_constant.lights[0] = 0; + push_constant.lights[1] = 0; + push_constant.lights[2] = 0; + push_constant.lights[3] = 0; + + uint32_t base_flags = 0; + + { + Light *light = p_lights; + + uint16_t light_count = 0; + while (light) { + + if (light->render_index_cache >= 0 && p_item->light_mask & light->item_mask && p_item->z_final >= light->z_min && p_item->z_final <= light->z_max && p_item->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { + + uint32_t light_index = light->render_index_cache; + push_constant.lights[light_count >> 2] |= light_index << ((light_count & 3) * 8); + light_count++; + if (light->mode == VS::CANVAS_LIGHT_MODE_MASK) { + base_flags |= FLAGS_USING_LIGHT_MASK; + } + if (light_count == MAX_LIGHTS_PER_ITEM) { + break; + } + } + light = light->next_ptr; + } + + base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT; + } + PipelineVariants *pipeline_variants = &shader.pipeline_variants; bool reclip = false; @@ -521,7 +569,8 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ const Item::Command *c = p_item->commands; while (c) { - push_constant.flags = 0; //reset on each command for sanity + push_constant.flags = base_flags; //reset on each command for sanity + push_constant.specular_shininess = 0xFFFFFFFF; switch (c->type) { case Item::Command::TYPE_RECT: { @@ -538,11 +587,17 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list); + texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list, push_constant.flags); texpixel_size.x = 1.0 / texpixel_size.x; texpixel_size.y = 1.0 / texpixel_size.y; } + if (rect->specular_shininess.a < 0.999) { + push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + } + + _update_specular_shininess(rect->specular_shininess, &push_constant.specular_shininess); + Rect2 src_rect; Rect2 dst_rect; @@ -594,10 +649,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ texpixel_size = Vector2(1, 1); } - push_constant.modulation[0] = rect->modulate.r * p_modulate.r; - push_constant.modulation[1] = rect->modulate.g * p_modulate.g; - push_constant.modulation[2] = rect->modulate.b * p_modulate.b; - push_constant.modulation[3] = rect->modulate.a; + push_constant.modulation[0] = rect->modulate.r * base_color.r; + push_constant.modulation[1] = rect->modulate.g * base_color.g; + push_constant.modulation[2] = rect->modulate.b * base_color.b; + push_constant.modulation[3] = rect->modulate.a * base_color.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -632,11 +687,17 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list); + texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list, push_constant.flags); texpixel_size.x = 1.0 / texpixel_size.x; texpixel_size.y = 1.0 / texpixel_size.y; } + if (np->specular_shininess.a < 0.999) { + push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + } + + _update_specular_shininess(np->specular_shininess, &push_constant.specular_shininess); + Rect2 src_rect; Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y); @@ -655,10 +716,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } } - push_constant.modulation[0] = np->color.r * p_modulate.r; - push_constant.modulation[1] = np->color.g * p_modulate.g; - push_constant.modulation[2] = np->color.b * p_modulate.b; - push_constant.modulation[3] = np->color.a * p_modulate.a; + push_constant.modulation[0] = np->color.r * base_color.r; + push_constant.modulation[1] = np->color.g * base_color.g; + push_constant.modulation[2] = np->color.b * base_color.b; + push_constant.modulation[3] = np->color.a * base_color.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -713,15 +774,21 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list); + texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list, push_constant.flags); texpixel_size.x = 1.0 / texpixel_size.x; texpixel_size.y = 1.0 / texpixel_size.y; } - push_constant.modulation[0] = p_modulate.r; - push_constant.modulation[1] = p_modulate.g; - push_constant.modulation[2] = p_modulate.b; - push_constant.modulation[3] = p_modulate.a; + if (polygon->specular_shininess.a < 0.999) { + push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + } + + _update_specular_shininess(polygon->specular_shininess, &push_constant.specular_shininess); + + push_constant.modulation[0] = base_color.r; + push_constant.modulation[1] = base_color.g; + push_constant.modulation[2] = base_color.b; + push_constant.modulation[3] = base_color.a; for (int j = 0; j < 4; j++) { push_constant.src_rect[j] = 0; @@ -755,9 +822,15 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ //bind textures { - _bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list); + _bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list, push_constant.flags); } + if (primitive->specular_shininess.a < 0.999) { + push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + } + + _update_specular_shininess(primitive->specular_shininess, &push_constant.specular_shininess); + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3, primitive->point_count) - 1]); for (uint32_t j = 0; j < MIN(3, primitive->point_count); j++) { @@ -765,7 +838,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.points[j * 2 + 1] = primitive->points[j].y; push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x; push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y; - Color col = primitive->colors[j] * p_modulate; + Color col = primitive->colors[j] * base_color; push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } @@ -779,7 +852,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.points[j * 2 + 1] = primitive->points[j + 1].y; push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x; push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y; - Color col = primitive->colors[j + 1] * p_modulate; + Color col = primitive->colors[j + 1] * base_color; push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } @@ -1107,12 +1180,12 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) { +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights) { Item *current_clip = NULL; RenderTargetFormat render_target_format = RENDER_TARGET_FORMAT_8_BIT_INT; - Transform2D canvas_transform_inverse = p_transform.affine_inverse(); + Transform2D canvas_transform_inverse = p_canvas_transform_inverse; RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); @@ -1153,7 +1226,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_skeleton_uniform_set, 1); } - _render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse, current_clip); + _render_item(draw_list, ci, render_target_format, texture_samples, canvas_transform_inverse, current_clip, p_lights); } RD::get_singleton()->draw_list_end(); @@ -1167,11 +1240,67 @@ void RasterizerCanvasRD::_update_canvas_state_uniform_set() { Vector<RD::Uniform> uniforms; - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(state.canvas_state_buffer); - uniforms.push_back(u); + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(state.canvas_state_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 1; + u.ids.push_back(state.lights_uniform_buffer); + uniforms.push_back(u); + } + + { + + RD::Uniform u_lights; + u_lights.type = RD::UNIFORM_TYPE_TEXTURE; + u_lights.binding = 2; + + RD::Uniform u_shadows; + u_shadows.type = RD::UNIFORM_TYPE_TEXTURE; + u_shadows.binding = 3; + + //lights + for (uint32_t i = 0; i < MAX_LIGHT_TEXTURES; i++) { + if (i < canvas_light_owner.get_rid_count()) { + CanvasLight *cl = canvas_light_owner.get_rid_by_index(i); + cl->texture_index = i; + RID rd_texture; + + if (cl->texture.is_valid()) { + rd_texture = storage->texture_get_rd_texture(cl->texture); + } + if (rd_texture.is_valid()) { + u_lights.ids.push_back(rd_texture); + } else { + u_lights.ids.push_back(default_textures.white_texture); + } + if (cl->shadow.texture.is_valid()) { + u_shadows.ids.push_back(cl->shadow.texture); + } else { + u_shadows.ids.push_back(default_textures.black_texture); + } + } else { + u_lights.ids.push_back(default_textures.white_texture); + u_shadows.ids.push_back(default_textures.black_texture); + } + } + + //in case there are more + for (uint32_t i = MAX_LIGHT_TEXTURES; i < canvas_light_owner.get_rid_count(); i++) { + CanvasLight *cl = canvas_light_owner.get_rid_by_index(i); + cl->texture_index = -1; //make invalid (no texture) + } + + uniforms.push_back(u_lights); + uniforms.push_back(u_shadows); + } state.canvas_state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 3); // uses index 3 } @@ -1182,6 +1311,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite //setup canvas state uniforms if needed _update_canvas_state_uniform_set(); + Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse(); { //update canvas state uniform buffer @@ -1194,9 +1324,77 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite 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; + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); } + //setup lights if exist + + { + + Light *l = p_light_list; + uint32_t index = 0; + + while (l) { + + if (index == MAX_RENDER_LIGHTS) { + l->render_index_cache = -1; + l = l->next_ptr; + continue; + } + + CanvasLight *clight = canvas_light_owner.getornull(l->light_internal); + if (!clight || clight->texture_index < 0) { //unused or invalid texture + l->render_index_cache = -1; + l = l->next_ptr; + ERR_CONTINUE(!clight); + } + Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse(); + + Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss + state.light_uniforms[index].position[0] = canvas_light_pos.x; + state.light_uniforms[index].position[1] = canvas_light_pos.y; + + _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix); + + state.light_uniforms[index].height = l->height * (p_canvas_transform.elements[0].length() + p_canvas_transform.elements[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss + for (int i = 0; i < 4; i++) { + state.light_uniforms[index].shadow_color[i] = l->shadow_color[i]; + 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 (clight->shadow.texture.is_valid()) { + state.light_uniforms[index].shadow_pixel_size = 1.0 / clight->shadow.size; + } else { + state.light_uniforms[index].shadow_pixel_size = 1.0; + } + state.light_uniforms[index].flags = clight->texture_index; + state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT; + + l->render_index_cache = index; + + index++; + 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); + } + } + //fill the list until rendering is possible. Item *ci = p_item_list; while (ci) { @@ -1205,7 +1403,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) { - _render_items(p_to_render_target, item_count, p_modulate, p_canvas_transform); + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); //then reset item_count = 0; } @@ -1224,6 +1422,292 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } +RID RasterizerCanvasRD::light_create() { + + CanvasLight canvas_light; + canvas_light.shadow.size = 0; + canvas_light.texture_index = -1; + return canvas_light_owner.make_rid(canvas_light); +} + +void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND(!cl); + if (cl->texture == p_texture) { + return; + } + + cl->texture = p_texture; + + //canvas state uniform set needs updating + if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) { + RD::get_singleton()->free(state.canvas_state_uniform_set); + } +} +void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND(!cl); + ERR_FAIL_COND(p_resolution < 64); + if (cl->shadow.texture.is_valid() == p_enable && p_resolution == cl->shadow.size) { + return; + } + + if (cl->shadow.texture.is_valid()) { + + RD::get_singleton()->free(cl->shadow.uniform_set); + cl->shadow.uniform_set = RID(); + + for (int i = 0; i < 4; i++) { + RD::get_singleton()->free(cl->shadow.render_fb[i]); + RD::get_singleton()->free(cl->shadow.render_textures[i]); + cl->shadow.render_fb[i] = RID(); + cl->shadow.render_textures[i] = RID(); + } + RD::get_singleton()->free(cl->shadow.fix_fb); + RD::get_singleton()->free(cl->shadow.texture); + + cl->shadow.fix_fb = RID(); + cl->shadow.texture = RID(); + } + + if (p_enable) { + + { //texture + RD::TextureFormat tf; + tf.type = RD::TEXTURE_TYPE_2D; + tf.width = p_resolution; + tf.height = 1; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.format = RD::DATA_FORMAT_R32_SFLOAT; + + cl->shadow.texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> fb_textures; + fb_textures.push_back(cl->shadow.texture); + cl->shadow.fix_fb = RD::get_singleton()->framebuffer_create(fb_textures); + } + { + RD::TextureFormat tf; + tf.type = RD::TEXTURE_TYPE_2D; + tf.width = p_resolution / 2; + tf.height = 1; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT; + //chunks to write + cl->shadow.render_depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + RD::Uniform tex_uniforms; + tex_uniforms.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + tex_uniforms.binding = 0; + + for (int i = 0; i < 4; i++) { + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.format = RD::DATA_FORMAT_R32_SFLOAT; + cl->shadow.render_textures[i] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> textures; + textures.push_back(cl->shadow.render_textures[i]); + textures.push_back(cl->shadow.render_depth); + cl->shadow.render_fb[i] = RD::get_singleton()->framebuffer_create(textures); + + tex_uniforms.ids.push_back(default_samplers.samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST][VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]); + tex_uniforms.ids.push_back(cl->shadow.render_textures[i]); + } + + Vector<RD::Uniform> tex_uniforms_set; + tex_uniforms_set.push_back(tex_uniforms); + cl->shadow.uniform_set = RD::get_singleton()->uniform_set_create(tex_uniforms_set, shadow_render.shader_fix.version_get_shader(shadow_render.shader_fix_version, 0), 0); + } + } + + //canvas state uniform set needs updating + if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) { + RD::get_singleton()->free(state.canvas_state_uniform_set); + } +} + +void RasterizerCanvasRD::light_update_shadow(RID p_rid, 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.texture.is_null()); + + for (int i = 0; i < 4; i++) { + + //make sure it remains orthogonal, makes easy to read angle later + + //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + + Vector<Color> cc; + cc.push_back(Color(p_far, p_far, p_far, 1.0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.render_fb[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, cc); + + CameraMatrix projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; + + real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; + + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } + + Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0)); + projection = projection * CameraMatrix(Transform().looking_at(cam_target, 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]; + } + } + + /*if (i == 0) + *p_xform_cache = projection;*/ + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + + OccluderPolygon *co = occluder_polygon_owner.getornull(instance->polygon); + + if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { + + instance = instance->next; + continue; + } + + _update_transform_2d_to_mat4(p_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(); + } + + Vector<Color> cc; + cc.push_back(Color(p_far, p_far, p_far, 1.0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fix_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, cc); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.shader_fix_pipeline); + RD::get_singleton()->draw_list_bind_index_array(draw_list, primitive_arrays.index_array[3]); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, cl->shadow.uniform_set, 0); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +RID RasterizerCanvasRD::occluder_polygon_create() { + + OccluderPolygon occluder; + occluder.point_count = 0; + occluder.cull_mode = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + return occluder_polygon_owner.make_rid(occluder); +} + +void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const PoolVector<Vector2> &p_lines) { + + OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); + ERR_FAIL_COND(!oc); + + if (oc->point_count != p_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); + RD::get_singleton()->free(oc->index_buffer); + + oc->vertex_array = RID(); + oc->vertex_buffer = RID(); + oc->index_array = RID(); + oc->index_buffer = RID(); + } + + if (p_lines.size()) { + + PoolVector<uint8_t> geometry; + PoolVector<uint8_t> indices; + int lc = p_lines.size(); + + geometry.resize(lc * 6 * sizeof(float)); + indices.resize(lc * 3 * sizeof(uint16_t)); + + { + PoolVector<uint8_t>::Write vw = geometry.write(); + float *vwptr = (float *)vw.ptr(); + PoolVector<uint8_t>::Write iw = indices.write(); + uint16_t *iwptr = (uint16_t *)iw.ptr(); + + PoolVector<Vector2>::Read lr = p_lines.read(); + + const int POLY_HEIGHT = 16384; + + for (int i = 0; i < lc / 2; i++) { + + vwptr[i * 12 + 0] = lr[i * 2 + 0].x; + vwptr[i * 12 + 1] = lr[i * 2 + 0].y; + vwptr[i * 12 + 2] = POLY_HEIGHT; + + vwptr[i * 12 + 3] = lr[i * 2 + 1].x; + vwptr[i * 12 + 4] = lr[i * 2 + 1].y; + vwptr[i * 12 + 5] = POLY_HEIGHT; + + vwptr[i * 12 + 6] = lr[i * 2 + 1].x; + vwptr[i * 12 + 7] = lr[i * 2 + 1].y; + vwptr[i * 12 + 8] = -POLY_HEIGHT; + + vwptr[i * 12 + 9] = lr[i * 2 + 0].x; + vwptr[i * 12 + 10] = lr[i * 2 + 0].y; + vwptr[i * 12 + 11] = -POLY_HEIGHT; + + iwptr[i * 6 + 0] = i * 4 + 0; + iwptr[i * 6 + 1] = i * 4 + 1; + iwptr[i * 6 + 2] = i * 4 + 2; + + iwptr[i * 6 + 3] = i * 4 + 2; + iwptr[i * 6 + 4] = i * 4 + 3; + iwptr[i * 6 + 5] = i * 4 + 0; + } + } + + //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush + + if (oc->vertex_array.is_null()) { + //create from scratch + //vertices + oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry); + + Vector<RID> buffer; + buffer.push_back(oc->vertex_buffer); + oc->vertex_array = RD::get_singleton()->vertex_array_create(4 * lc / 2, shadow_render.vertex_format, buffer); + //indices + + oc->index_buffer = RD::get_singleton()->index_buffer_create(3 * lc, RD::INDEX_BUFFER_FORMAT_UINT16, indices); + oc->index_array = RD::get_singleton()->index_array_create(oc->index_buffer, 0, 3 * lc); + + } else { + //update existing + PoolVector<uint8_t>::Read vr = geometry.read(); + RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, geometry.size(), vr.ptr()); + PoolVector<uint8_t>::Read ir = indices.read(); + RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir.ptr()); + } + } +} +void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) { + OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); + ERR_FAIL_COND(!oc); + oc->cull_mode = p_mode; +} + void RasterizerCanvasRD::update() { _dispose_bindings(); } @@ -1422,6 +1906,59 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, 0); } + { //shadow rendering + Vector<String> versions; + versions.push_back(String()); //no versions + shadow_render.shader.initialize(versions); + + { + Vector<RD::AttachmentFormat> attachments; + + RD::AttachmentFormat af_color; + af_color.format = RD::DATA_FORMAT_R32_SFLOAT; + af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + attachments.push_back(af_color); + + shadow_render.framebuffer_fix_format = RD::get_singleton()->framebuffer_format_create(attachments); + + RD::AttachmentFormat af_depth; + af_depth.format = RD::DATA_FORMAT_D24_UNORM_S8_UINT; + af_depth.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT; + af_depth.usage_flags = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + attachments.push_back(af_depth); + + shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); + } + + //pipelines + Vector<RD::VertexDescription> vf; + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + vd.location = 0; + vd.offset = 0; + vd.stride = sizeof(float) * 3; + vf.push_back(vd); + shadow_render.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++) { + RD::PipelineRasterizationState rs; + rs.cull_mode = i == 0 ? RD::POLYGON_CULL_DISABLED : (i == 1 ? RD::POLYGON_CULL_FRONT : RD::POLYGON_CULL_BACK); + RD::PipelineDepthStencilState ds; + 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.shader_fix.initialize(versions); + shadow_render.shader_fix_version = shadow_render.shader_fix.version_create(); + shadow_render.shader_fix_pipeline = RD::get_singleton()->render_pipeline_create(shadow_render.shader_fix.version_get_shader(shadow_render.shader_fix_version, 0), shadow_render.framebuffer_fix_format, RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } + { //bindings bindings.id_generator = 0; //generate for 0 @@ -1429,6 +1966,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { //state allocate state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer)); + state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * MAX_RENDER_LIGHTS); } } @@ -1491,6 +2029,27 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { ERR_FAIL_COND(sizeof(PushConstant) != 128); } +bool RasterizerCanvasRD::free(RID p_rid) { + + if (canvas_light_owner.owns(p_rid)) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND_V(!cl, false); + light_set_use_shadow(p_rid, false, 64); + canvas_light_owner.free(p_rid); + //canvas state uniform set needs updating + if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) { + RD::get_singleton()->free(state.canvas_state_uniform_set); + } + } else if (occluder_polygon_owner.owns(p_rid)) { + occluder_polygon_set_shape_as_lines(p_rid, PoolVector<Vector2>()); + occluder_polygon_owner.free(p_rid); + } else { + return false; + } + + return true; +} + RasterizerCanvasRD::~RasterizerCanvasRD() { //canvas state diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.h b/servers/visual/rasterizer/rasterizer_canvas_rd.h index 91870a20fd..59193f2a68 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.h +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.h @@ -5,6 +5,8 @@ #include "servers/visual/rasterizer/rasterizer_storage_rd.h" #include "servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h" #include "servers/visual/rasterizer/shaders/canvas.glsl.gen.h" +#include "servers/visual/rasterizer/shaders/canvas_occlusion.glsl.gen.h" +#include "servers/visual/rasterizer/shaders/canvas_occlusion_fix.glsl.gen.h" #include "servers/visual/rendering_device.h" class RasterizerCanvasRD : public RasterizerCanvas { @@ -37,13 +39,37 @@ 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), FLAGS_USE_PIXEL_SNAP = (1 << 14), FLAGS_USE_SKELETON = (1 << 15), FLAGS_NINEPATCH_H_MODE_SHIFT = 16, - FLAGS_NINEPATCH_V_MODE_SHIFT = 18 + FLAGS_NINEPATCH_V_MODE_SHIFT = 18, + FLAGS_LIGHT_COUNT_SHIFT = 20, + + FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26), + FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27) + + }; + + enum { + LIGHT_FLAGS_TEXTURE_MASK = 0xFFFF, + LIGHT_FLAGS_BLEND_SHIFT = 16, + LIGHT_FLAGS_BLEND_MASK = (3 << 16), + LIGHT_FLAGS_BLEND_MODE_ADD = (0 << 16), + LIGHT_FLAGS_BLEND_MODE_SUB = (1 << 16), + LIGHT_FLAGS_BLEND_MODE_MIX = (2 << 16), + LIGHT_FLAGS_BLEND_MODE_MASK = (3 << 16) + }; + + enum { + MAX_RENDER_ITEMS = 256 * 1024, + MAX_LIGHT_TEXTURES = 1024, + MAX_LIGHTS_PER_ITEM = 16, + MAX_RENDER_LIGHTS = 256 }; /****************/ @@ -183,18 +209,66 @@ class RasterizerCanvasRD : public RasterizerCanvas { /**** LIGHTING ****/ /******************/ - enum { - LIGHT_GRID_WIDTH = 16, - LIGHT_GRID_HEIGHT = 16, - MAX_LIGHTS = 128 + struct CanvasLight { + + int32_t texture_index; + RID texture; + struct { + int size; + RID texture; + + RID render_depth; + RID render_fb[4]; + RID render_textures[4]; + RID fix_fb; + RID uniform_set; + + } shadow; }; + RID_Owner<CanvasLight> canvas_light_owner; + + struct ShadowRenderPushConstant { + float projection[16]; + float modelview[16]; + }; + + struct OccluderPolygon { + + VS::CanvasOccluderPolygonCullMode cull_mode; + int point_count; + RID vertex_buffer; + RID vertex_array; + RID index_buffer; + RID index_array; + }; + + struct LightUniform { + float matrix[8]; //light to texture coordinate matrix + float color[4]; + float shadow_color[4]; + float position[2]; + uint32_t flags; //index to light texture + float height; + float shadow_softness; + float shadow_pixel_size; + float pad[2]; + }; + + RID_Owner<OccluderPolygon> occluder_polygon_owner; + struct { - RID grid_texture; - RID grid_buffer; - PoolVector<uint8_t> grid_texture_data; - PoolVector<uint8_t> grid_buffer_data; - } lighting; + CanvasOcclusionShaderRD shader; + RID shader_version; + RID render_pipelines[3]; + RD::VertexFormatID vertex_format; + RD::FramebufferFormatID framebuffer_format; + + CanvasOcclusionFixShaderRD shader_fix; + RD::FramebufferFormatID framebuffer_fix_format; + RID shader_fix_version; + RID shader_fix_pipeline; + } shadow_render; /***************/ /**** STATE ****/ @@ -208,12 +282,16 @@ class RasterizerCanvasRD : public RasterizerCanvas { struct Buffer { float canvas_transform[16]; float screen_transform[16]; + float canvas_normal_transform[16]; + float canvas_modulate[4]; //uint32_t light_count; //uint32_t pad[3]; }; + + LightUniform light_uniforms[MAX_RENDER_LIGHTS]; + + RID lights_uniform_buffer; RID canvas_state_buffer; - //light buffer - RID canvas_state_light_buffer; //uniform set for all the above RID canvas_state_uniform_set; @@ -234,8 +312,8 @@ class RasterizerCanvasRD : public RasterizerCanvas { }; //primitive struct { - float points[6]; // vec2 points[4] - float uvs[6]; // vec2 points[4] + float points[6]; // vec2 points[3] + float uvs[6]; // vec2 points[3] uint32_t colors[6]; // colors encoded as half }; }; @@ -248,21 +326,19 @@ class RasterizerCanvasRD : public RasterizerCanvas { float skeleton_inverse[16]; }; - enum { - MAX_RENDER_ITEMS = 256 * 1024 - }; - Item *items[MAX_RENDER_ITEMS]; - Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list); - void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip); - void _render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform); + Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags); + void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights); + void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights); - void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); - void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); + _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); + _FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); - void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4); - void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); + _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); + + _FORCE_INLINE_ void _update_specular_shininess(const Color &p_transform, uint32_t *r_ss); void _update_canvas_state_uniform_set(); @@ -273,21 +349,23 @@ 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); - RID light_internal_create() { return RID(); } - void light_internal_update(RID p_rid, Light *p_light) {} - void light_internal_free(RID p_rid) {} + RID light_create(); + void light_set_texture(RID p_rid, RID p_texture); + void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution); + void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders); + + RID occluder_polygon_create(); + void occluder_polygon_set_shape_as_lines(RID p_occluder, const PoolVector<Vector2> &p_lines); + void occluder_polygon_set_cull_mode(RID p_occluder, VS::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); void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){}; - void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) {} - - void reset_canvas() {} - void draw_window_margins(int *p_margins, RID *p_margin_textures) {} void update(); + bool free(RID p_rid); RasterizerCanvasRD(RasterizerStorageRD *p_storage); ~RasterizerCanvasRD(); }; diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.h b/servers/visual/rasterizer/rasterizer_storage_rd.h index 4f81a4cce9..bb9e20861f 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer/rasterizer_storage_rd.h @@ -647,15 +647,6 @@ public: Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); - /* CANVAS SHADOW */ - - RID canvas_light_shadow_buffer_create(int p_width) { return RID(); } - - /* LIGHT SHADOW MAPPING */ - - RID canvas_light_occluder_create() { return RID(); } - void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {} - VS::InstanceType get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; diff --git a/servers/visual/rasterizer/shaders/SCsub b/servers/visual/rasterizer/shaders/SCsub index 62a4c2a0ba..ef1df0c203 100644 --- a/servers/visual/rasterizer/shaders/SCsub +++ b/servers/visual/rasterizer/shaders/SCsub @@ -4,3 +4,5 @@ Import('env') if 'RD_GLSL' in env['BUILDERS']: env.RD_GLSL('canvas.glsl'); + env.RD_GLSL('canvas_occlusion.glsl'); + env.RD_GLSL('canvas_occlusion_fix.glsl'); diff --git a/servers/visual/rasterizer/shaders/canvas.glsl b/servers/visual/rasterizer/shaders/canvas.glsl index 734974ba81..6b1485c86b 100644 --- a/servers/visual/rasterizer/shaders/canvas.glsl +++ b/servers/visual/rasterizer/shaders/canvas.glsl @@ -23,6 +23,7 @@ layout(location = 7) in vec4 bone_weights_attrib; layout(location=0) out vec2 uv_interp; layout(location=1) out vec4 color_interp; +layout(location=2) out vec2 vertex_interp; #ifdef USE_NINEPATCH @@ -206,12 +207,12 @@ VERTEX_SHADER_CODE #endif #endif + vertex = (canvas_data.canvas_transform * vec4(vertex,0.0,1.0)).xy; + + vertex_interp = vertex; uv_interp = uv; -#if !defined(SKIP_TRANSFORM_USED) - gl_Position = (canvas_data.screen_transform * canvas_data.canvas_transform) * vec4(vertex,0.0,1.0); -#else - gl_Position = vec4(vertex,0.0,1.0); -#endif + + gl_Position = canvas_data.screen_transform * vec4(vertex,0.0,1.0); #ifdef USE_POINT_SIZE gl_PointSize=point_size; @@ -232,6 +233,7 @@ VERSION_DEFINES layout(location=0) in vec2 uv_interp; layout(location=1) in vec4 color_interp; +layout(location=2) in vec2 vertex_interp; #ifdef USE_NINEPATCH @@ -315,6 +317,7 @@ void main() { vec4 color = color_interp; vec2 uv = uv_interp; + vec2 vertex = vertex_interp; #if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) @@ -347,6 +350,8 @@ void main() { #endif + uint light_count = (draw_data.flags>>FLAGS_LIGHT_COUNT_SHIFT)&0xF; //max 16 lights + vec3 normal; @@ -357,18 +362,33 @@ void main() { bool normal_used = false; #endif -#if 0 - if (false /*normal_used || canvas_data.light_count > 0*/ ) { - normal.xy = texture(sampler2D(normal_texture,texture_sampler ), uv).xy * 2.0 - 1.0; + + if (normal_used || (light_count > 0 && 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; } else { -#endif normal = vec3(0.0, 0.0, 1.0); -#if 0 } + + vec4 specular_shininess; + +#if defined(SPECULAR_SHININESS_USED) + + bool specular_shininess_used = true; +#else + bool specular_shininess_used = false; #endif + if (specular_shininess_used || (light_count > 0 && 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; + } else { + specular_shininess = vec4(1.0); + } + + #if defined(SCREEN_UV_USED) vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; #endif @@ -392,13 +412,104 @@ FRAGMENT_SHADER_CODE #endif } -#if 0 - if (canvas_data.light_count > 0 ) { - //do lighting + if (normal_used) { + //convert by item transform + normal.xy = mat2(normalize(draw_data.world_x), normalize(draw_data.world_y)) * normal.xy; + //convert by canvas transform + normal = normalize((canvas_data.canvas_normal_transform * vec4(normal,0.0)).xyz); + } + + vec4 base_color=color; + if (bool(draw_data.flags&FLAGS_USING_LIGHT_MASK)) { + color=vec4(0.0); //inivisible by default due to using light mask } -#endif - //color.rgb *= color.a; + + color*=canvas_data.canvas_modulation; + + for(uint i=0;i<light_count;i++) { + uint light_base; + if (i<8) { + if (i<4) { + light_base=draw_data.lights[0]; + } else { + light_base=draw_data.lights[1]; + } + } else { + if (i<12) { + light_base=draw_data.lights[2]; + } else { + light_base=draw_data.lights[3]; + } + } + light_base>>=(i&3)*8; + light_base&=0xFF; + +#define LIGHT_FLAGS_BLEND_MASK (3<<16) +#define LIGHT_FLAGS_BLEND_MODE_ADD (0<<16) +#define LIGHT_FLAGS_BLEND_MODE_SUB (1<<16) +#define LIGHT_FLAGS_BLEND_MODE_MIX (2<<16) +#define LIGHT_FLAGS_BLEND_MODE_MASK (3<<16) + + + vec2 tex_uv = (vec4(vertex,0.0,1.0) * mat4(light_array.data[light_base].matrix[0],light_array.data[light_base].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. + uint texture_idx = light_array.data[light_base].flags&LIGHT_FLAGS_TEXTURE_MASK; + vec4 light_color = texture(sampler2D(light_textures[texture_idx],texture_sampler),tex_uv); + vec4 light_base_color = light_array.data[light_base].color; + light_color.rgb*=light_base_color.rgb*light_base_color.a; + + if (normal_used) { + + vec3 light_pos = vec3(light_array.data[light_base].position,light_array.data[light_base].height); + vec3 pos = vec3(vertex,0.0); + 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; + } + + } + + if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { + //if outside the light texture, light color is zero + light_color.a = 0.0; + } + + 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; + } + } + frag_color = color; } diff --git a/servers/visual/rasterizer/shaders/canvas_occlusion.glsl b/servers/visual/rasterizer/shaders/canvas_occlusion.glsl new file mode 100644 index 0000000000..fb35f16971 --- /dev/null +++ b/servers/visual/rasterizer/shaders/canvas_occlusion.glsl @@ -0,0 +1,38 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +layout(location = 0) in highp vec3 vertex; + +layout(push_constant, binding = 0, std430) uniform Constants { + + mat4 modelview; + mat4 projection; +} constants; + +layout(location = 0) out highp float depth; + +void main() { + + highp vec4 vtx = (constants.modelview * vec4(vertex, 1.0)); + depth = length(vtx.xy); + + gl_Position = constants.projection * vtx; + +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +layout(location = 0) in highp float depth; +layout(location = 0) out highp float distance_buf; + +void main() { + + distance_buf=depth; +} diff --git a/servers/visual/rasterizer/shaders/canvas_occlusion_fix.glsl b/servers/visual/rasterizer/shaders/canvas_occlusion_fix.glsl new file mode 100644 index 0000000000..48757bb68a --- /dev/null +++ b/servers/visual/rasterizer/shaders/canvas_occlusion_fix.glsl @@ -0,0 +1,56 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +layout(location = 0) out highp float u; + +void main() { + + if (gl_VertexIndex==0) { + u=0.0; + gl_Position=vec4(-1.0,-1.0,0.0,1.0); + } else if (gl_VertexIndex==1) { + u=0.0; + gl_Position=vec4(-1.0,1.0,0.0,1.0); + } else if (gl_VertexIndex==2) { + u=1.0; + gl_Position=vec4(1.0,1.0,0.0,1.0); + } else { + u=1.0; + gl_Position=vec4(1.0,-1.0,0.0,1.0); + } +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +#define PI 3.14159265359 + +layout(set=0, binding=0) uniform sampler2D textures[4]; +layout(location = 0) in highp float u; +layout(location = 0) out highp float distance; + +void main() { + + //0-1 in the texture we are writing to represents a circle, 0-2PI) + //obtain the quarter circle from the source textures + highp float sub_angle = ((mod(u,0.25)/0.25)*2.0-1.0)*(PI/4.0); + highp float x=tan(sub_angle)*0.5+0.5; + + float depth; + if (u<0.25) { + depth=texture(textures[0],vec2(x,0.0)).x; + } else if (u<0.50) { + depth=texture(textures[1],vec2(x,0.0)).x; + } else if (u<0.75) { + depth=texture(textures[2],vec2(x,0.0)).x; + } else { + depth=texture(textures[3],vec2(x,0.0)).x; + } + distance=depth; +} diff --git a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl index e205170292..cf8a17ce1e 100644 --- a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl +++ b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl @@ -1,8 +1,10 @@ /* SET0: Per draw primitive settings */ +#define M_PI 3.14159265359 -#define MAX_LIGHTS 128 +#define MAX_LIGHT_TEXTURES 1024 +#define MAX_RENDER_LIGHTS 256 #define FLAGS_INSTANCING_STRIDE_MASK 0xF #define FLAGS_INSTANCING_ENABLED (1<<4) @@ -13,16 +15,19 @@ #define FLAGS_CLIP_RECT_UV (1 << 9) #define FLAGS_TRANSPOSE_RECT (1 << 10) +#define FLAGS_USING_LIGHT_MASK (1 << 11) #define FLAGS_NINEPACH_DRAW_CENTER (1 << 12) #define FLAGS_USING_PARTICLES (1 << 13) #define FLAGS_USE_PIXEL_SNAP (1 << 14) - #define FLAGS_NINEPATCH_H_MODE_SHIFT 16 #define FLAGS_NINEPATCH_V_MODE_SHIFT 18 #define FLAGS_LIGHT_COUNT_SHIFT 20 +#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26) +#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) + layout(push_constant, binding = 0, std430) uniform DrawData { vec2 world_x; vec2 world_y; @@ -77,26 +82,35 @@ layout(set = 2, binding = 1, std140) uniform SkeletonData { layout(set = 3, binding = 0, std140) uniform CanvasData { mat4 canvas_transform; mat4 screen_transform; + mat4 canvas_normal_transform; + vec4 canvas_modulation; //uint light_count; } canvas_data; +#define LIGHT_FLAGS_TEXTURE_MASK 0xFFFF +#define LIGHT_FLAGS_BLEND_MASK (3<<16) +#define LIGHT_FLAGS_BLEND_MODE_ADD (0<<16) +#define LIGHT_FLAGS_BLEND_MODE_SUB (1<<16) +#define LIGHT_FLAGS_BLEND_MODE_MIX (2<<16) +#define LIGHT_FLAGS_BLEND_MODE_MASK (3<<16) + + struct Light { - // light matrices - mat4 light_matrix; - mat4 light_local_matrix; - mat4 shadow_matrix; - vec4 light_color; - vec4 light_shadow_color; - vec2 light_pos; - float shadowpixel_size; - float shadow_gradient; - float light_height; - float light_outside_alpha; - float shadow_distance_mult; + mat2x4 matrix; //light to texture coordinate matrix + vec4 color; + vec4 shadow_color; + vec2 position; + uint flags; //index to light texture + float height; + float shadow_softness; + float shadow_pixel_size; + float pad0; + float pad1; }; layout(set = 3, binding = 1, std140) uniform LightData { - Light lights[MAX_LIGHTS]; -} light_data; + Light data[MAX_RENDER_LIGHTS]; +} light_array; -layout(set = 3, binding = 2) uniform texture2D light_textures[MAX_LIGHTS]; +layout(set = 3, binding = 2) uniform texture2D light_textures[MAX_LIGHT_TEXTURES]; +layout(set = 3, binding = 3) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES]; |