Add 2D shadows and canvas SDF to OpenGL3 renderer
This is an initial implementation based on the current RD implementation Performance will improve later
This commit is contained in:
parent
282e50ac88
commit
2ec234ff67
19 changed files with 1322 additions and 223 deletions
|
@ -117,16 +117,12 @@ CopyEffects::~CopyEffects() {
|
|||
void CopyEffects::copy_to_rect(const Rect2 &p_rect) {
|
||||
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
|
||||
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
|
||||
glBindVertexArray(quad_array);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
glBindVertexArray(0);
|
||||
draw_screen_quad();
|
||||
}
|
||||
|
||||
void CopyEffects::copy_screen() {
|
||||
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
|
||||
glBindVertexArray(screen_triangle_array);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
draw_screen_triangle();
|
||||
}
|
||||
|
||||
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
|
||||
|
@ -158,8 +154,19 @@ void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
|
|||
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
|
||||
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
|
||||
copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
|
||||
draw_screen_quad();
|
||||
}
|
||||
|
||||
void CopyEffects::draw_screen_triangle() {
|
||||
glBindVertexArray(screen_triangle_array);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void CopyEffects::draw_screen_quad() {
|
||||
glBindVertexArray(quad_array);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
#endif // GLES3_ENABLED
|
||||
|
|
|
@ -65,6 +65,8 @@ public:
|
|||
void copy_screen();
|
||||
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
|
||||
void set_color(const Color &p_color, const Rect2i &p_region);
|
||||
void draw_screen_triangle();
|
||||
void draw_screen_quad();
|
||||
};
|
||||
|
||||
} //namespace GLES3
|
||||
|
|
|
@ -36,26 +36,13 @@
|
|||
#include "rasterizer_scene_gles3.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/math/geometry_2d.h"
|
||||
#include "servers/rendering/rendering_server_default.h"
|
||||
#include "storage/config.h"
|
||||
#include "storage/material_storage.h"
|
||||
#include "storage/mesh_storage.h"
|
||||
#include "storage/texture_storage.h"
|
||||
|
||||
#ifndef GLES_OVER_GL
|
||||
#define glClearDepth glClearDepthf
|
||||
#endif
|
||||
|
||||
//static const GLenum gl_primitive[] = {
|
||||
// GL_POINTS,
|
||||
// GL_LINES,
|
||||
// GL_LINE_STRIP,
|
||||
// GL_LINE_LOOP,
|
||||
// GL_TRIANGLES,
|
||||
// GL_TRIANGLE_STRIP,
|
||||
// GL_TRIANGLE_FAN
|
||||
//};
|
||||
|
||||
void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
|
||||
p_mat4[0] = p_transform.columns[0][0];
|
||||
p_mat4[1] = p_transform.columns[0][1];
|
||||
|
@ -174,7 +161,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
state.light_uniforms[index].position[0] = -canvas_light_dir.x;
|
||||
state.light_uniforms[index].position[1] = -canvas_light_dir.y;
|
||||
|
||||
//_update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix);
|
||||
_update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix);
|
||||
|
||||
state.light_uniforms[index].height = l->height; //0..1 here
|
||||
|
||||
|
@ -185,8 +172,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
|
||||
state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
|
||||
|
||||
/*
|
||||
if (state.shadow_fb.is_valid()) {
|
||||
if (state.shadow_fb != 0) {
|
||||
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;
|
||||
|
@ -195,15 +181,13 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
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;
|
||||
|
||||
|
@ -252,24 +236,22 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
|
||||
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;
|
||||
}
|
||||
*/
|
||||
if (state.shadow_fb != 0) {
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
||||
if (clight->texture.is_valid()) {
|
||||
Rect2 atlas_rect = GLES3::TextureStorage::get_singleton()->texture_atlas_get_texture_rect(clight->texture);
|
||||
|
@ -313,6 +295,13 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
}
|
||||
glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 2);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_atlas);
|
||||
GLuint shadow_tex = state.shadow_texture;
|
||||
if (shadow_tex == 0) {
|
||||
GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
|
||||
shadow_tex = tex->tex_id;
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 3);
|
||||
glBindTexture(GL_TEXTURE_2D, shadow_tex);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -342,8 +331,6 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
|
||||
state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
|
||||
|
||||
glViewport(0, 0, render_target_size.x, render_target_size.y);
|
||||
|
||||
state_buffer.time = state.time;
|
||||
state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel;
|
||||
|
||||
|
@ -366,6 +353,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height;
|
||||
|
||||
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
|
||||
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].state_ubo);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
|
||||
|
||||
|
@ -375,11 +363,17 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 5);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_storage->render_target_get_sdf_texture(p_to_render_target));
|
||||
|
||||
{
|
||||
state.default_filter = p_default_filter;
|
||||
state.default_repeat = p_default_repeat;
|
||||
}
|
||||
|
||||
Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
|
||||
glViewport(0, 0, render_target_size.x, render_target_size.y);
|
||||
|
||||
r_sdf_used = false;
|
||||
int item_count = 0;
|
||||
bool backbuffer_cleared = false;
|
||||
|
@ -621,6 +615,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
|||
CanvasShaderGLES3::ShaderVariant variant = state.canvas_instance_batches[i].shader_variant;
|
||||
uint64_t specialization = 0;
|
||||
specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
|
||||
specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
|
||||
_bind_material(material_data, variant, specialization);
|
||||
|
||||
GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
|
||||
|
@ -1395,28 +1390,516 @@ void RasterizerCanvasGLES3::light_set_texture(RID p_rid, RID p_texture) {
|
|||
}
|
||||
|
||||
void RasterizerCanvasGLES3::light_set_use_shadow(RID p_rid, bool p_enable) {
|
||||
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
|
||||
ERR_FAIL_COND(!cl);
|
||||
|
||||
cl->shadow.enabled = p_enable;
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::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) {
|
||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||
|
||||
CanvasLight *cl = canvas_light_owner.get_or_null(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(data.max_lights_per_render * 2);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
|
||||
glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2);
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
|
||||
glClearColor(p_far, p_far, p_far, 1.0);
|
||||
glClearDepth(1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_CULL_FACE);
|
||||
RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
|
||||
|
||||
CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA;
|
||||
shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
|
||||
|
||||
Projection 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::deg_to_rad(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::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
|
||||
|
||||
projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant);
|
||||
|
||||
static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, directions[i].x, directions[i].y, shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, p_far, shadow_render.shader_version, variant);
|
||||
|
||||
LightOccluderInstance *instance = p_occluders;
|
||||
|
||||
while (instance) {
|
||||
OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
|
||||
|
||||
if (!co || co->vertex_array == 0 || !(p_light_mask & instance->light_mask)) {
|
||||
instance = instance->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform2D modelview = p_light_xform * instance->xform_cache;
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
|
||||
|
||||
if (co->cull_mode != cull_mode) {
|
||||
if (co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
} else {
|
||||
if (cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
|
||||
// Last time was disabled, so enable and set proper face.
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
glCullFace(co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK);
|
||||
}
|
||||
cull_mode = co->cull_mode;
|
||||
}
|
||||
|
||||
glBindVertexArray(co->vertex_array);
|
||||
glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
instance = instance->next;
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::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) {
|
||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||
|
||||
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
|
||||
ERR_FAIL_COND(!cl->shadow.enabled);
|
||||
|
||||
_update_shadow_atlas();
|
||||
|
||||
Vector2 light_dir = p_light_xform.columns[1].normalized();
|
||||
|
||||
Vector2 center = p_clip_rect.get_center();
|
||||
|
||||
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(data.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.orthogonal();
|
||||
|
||||
to_light_xform.invert();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
|
||||
glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2);
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
|
||||
glClearColor(1.0, 1.0, 1.0, 1.0);
|
||||
glClearDepth(1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_CULL_FACE);
|
||||
RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
|
||||
|
||||
CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA;
|
||||
shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
|
||||
|
||||
Projection projection;
|
||||
projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
|
||||
projection = projection * Projection(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
|
||||
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, 0.0, 1.0, shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, distance, shadow_render.shader_version, variant);
|
||||
|
||||
LightOccluderInstance *instance = p_occluders;
|
||||
|
||||
while (instance) {
|
||||
OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
|
||||
|
||||
if (!co || co->vertex_array == 0 || !(p_light_mask & instance->light_mask)) {
|
||||
instance = instance->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform2D modelview = to_light_xform * instance->xform_cache;
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
|
||||
|
||||
if (co->cull_mode != cull_mode) {
|
||||
if (co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
} else {
|
||||
if (cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
|
||||
// Last time was disabled, so enable and set proper face.
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
glCullFace(co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK);
|
||||
}
|
||||
cull_mode = co->cull_mode;
|
||||
}
|
||||
|
||||
glBindVertexArray(co->vertex_array);
|
||||
glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
instance = instance->next;
|
||||
}
|
||||
|
||||
Transform2D to_shadow;
|
||||
to_shadow.columns[0].x = 1.0 / -(half_size * 2.0);
|
||||
to_shadow.columns[2].x = 0.5;
|
||||
|
||||
cl->shadow.directional_xform = to_shadow * to_light_xform;
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::_update_shadow_atlas() {
|
||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||
|
||||
if (state.shadow_fb == 0) {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glGenFramebuffers(1, &state.shadow_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
|
||||
|
||||
glGenRenderbuffers(1, &state.shadow_depth_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, state.shadow_depth_buffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, state.shadow_texture_size, data.max_lights_per_render * 2);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, state.shadow_depth_buffer);
|
||||
|
||||
glGenTextures(1, &state.shadow_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, state.shadow_texture);
|
||||
if (config->float_texture_supported) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, state.shadow_texture_size, data.max_lights_per_render * 2, 0, GL_RED, GL_FLOAT, nullptr);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, state.shadow_texture_size, data.max_lights_per_render * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, state.shadow_texture, 0);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
glDeleteFramebuffers(1, &state.shadow_fb);
|
||||
glDeleteTextures(1, &state.shadow_texture);
|
||||
glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
|
||||
state.shadow_fb = 0;
|
||||
state.shadow_texture = 0;
|
||||
state.shadow_depth_buffer = 0;
|
||||
WARN_PRINT("Could not create CanvasItem shadow atlas, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) {
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
|
||||
GLuint fb = texture_storage->render_target_get_sdf_framebuffer(p_render_target);
|
||||
Rect2i rect = texture_storage->render_target_get_sdf_rect(p_render_target);
|
||||
|
||||
Transform2D to_sdf;
|
||||
to_sdf.columns[0] *= rect.size.width;
|
||||
to_sdf.columns[1] *= rect.size.height;
|
||||
to_sdf.columns[2] = rect.position;
|
||||
|
||||
Transform2D to_clip;
|
||||
to_clip.columns[0] *= 2.0;
|
||||
to_clip.columns[1] *= 2.0;
|
||||
to_clip.columns[2] = -Vector2(1.0, 1.0);
|
||||
|
||||
to_clip = to_clip * to_sdf.affine_inverse();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
glViewport(0, 0, rect.size.width, rect.size.height);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
CanvasOcclusionShaderGLES3::ShaderVariant variant = CanvasOcclusionShaderGLES3::MODE_SDF;
|
||||
shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
|
||||
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, Projection(), shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, 0.0, 0.0, shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, 0.0, shadow_render.shader_version, variant);
|
||||
|
||||
LightOccluderInstance *instance = p_occluders;
|
||||
|
||||
while (instance) {
|
||||
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(instance->occluder);
|
||||
|
||||
if (!oc || oc->sdf_vertex_array == 0) {
|
||||
instance = instance->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform2D modelview = to_clip * instance->xform_cache;
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
|
||||
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
|
||||
|
||||
glBindVertexArray(oc->sdf_vertex_array);
|
||||
glDrawElements(oc->sdf_is_lines ? GL_LINES : GL_TRIANGLES, oc->sdf_index_count, GL_UNSIGNED_INT, 0);
|
||||
|
||||
instance = instance->next;
|
||||
}
|
||||
|
||||
texture_storage->render_target_sdf_process(p_render_target); //done rendering, process it
|
||||
glBindVertexArray(0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
RID RasterizerCanvasGLES3::occluder_polygon_create() {
|
||||
return RID();
|
||||
OccluderPolygon occluder;
|
||||
|
||||
return occluder_polygon_owner.make_rid(occluder);
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
|
||||
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
|
||||
ERR_FAIL_COND(!oc);
|
||||
|
||||
Vector<Vector2> lines;
|
||||
|
||||
if (p_points.size()) {
|
||||
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 != 0) {
|
||||
glDeleteVertexArrays(1, &oc->vertex_array);
|
||||
glDeleteBuffers(1, &oc->vertex_buffer);
|
||||
glDeleteBuffers(1, &oc->index_buffer);
|
||||
|
||||
oc->vertex_array = 0;
|
||||
oc->vertex_buffer = 0;
|
||||
oc->index_buffer = 0;
|
||||
}
|
||||
|
||||
if (lines.size()) {
|
||||
Vector<uint8_t> geometry;
|
||||
Vector<uint8_t> indices;
|
||||
int lc = lines.size();
|
||||
|
||||
geometry.resize(lc * 6 * sizeof(float));
|
||||
indices.resize(lc * 3 * sizeof(uint16_t));
|
||||
|
||||
{
|
||||
uint8_t *vw = geometry.ptrw();
|
||||
float *vwptr = reinterpret_cast<float *>(vw);
|
||||
uint8_t *iw = indices.ptrw();
|
||||
uint16_t *iwptr = (uint16_t *)iw;
|
||||
|
||||
const Vector2 *lr = lines.ptr();
|
||||
|
||||
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 (oc->vertex_array == 0) {
|
||||
oc->line_point_count = lc;
|
||||
glGenVertexArrays(1, &oc->vertex_array);
|
||||
glBindVertexArray(oc->vertex_array);
|
||||
glGenBuffers(1, &oc->vertex_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
|
||||
|
||||
glGenBuffers(1, &oc->index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
|
||||
glBindVertexArray(0);
|
||||
} else {
|
||||
glBindVertexArray(oc->vertex_array);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
// sdf
|
||||
|
||||
Vector<int> sdf_indices;
|
||||
|
||||
if (p_points.size()) {
|
||||
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 != 0) {
|
||||
glDeleteVertexArrays(1, &oc->sdf_vertex_array);
|
||||
glDeleteBuffers(1, &oc->sdf_vertex_buffer);
|
||||
glDeleteBuffers(1, &oc->sdf_index_buffer);
|
||||
|
||||
oc->sdf_vertex_array = 0;
|
||||
oc->sdf_vertex_buffer = 0;
|
||||
oc->sdf_index_buffer = 0;
|
||||
|
||||
oc->sdf_index_count = sdf_indices.size();
|
||||
oc->sdf_point_count = p_points.size();
|
||||
}
|
||||
|
||||
if (sdf_indices.size()) {
|
||||
if (oc->sdf_vertex_array == 0) {
|
||||
oc->sdf_index_count = sdf_indices.size();
|
||||
oc->sdf_point_count = p_points.size();
|
||||
glGenVertexArrays(1, &oc->sdf_vertex_array);
|
||||
glBindVertexArray(oc->sdf_vertex_array);
|
||||
glGenBuffers(1, &oc->sdf_vertex_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
|
||||
|
||||
glGenBuffers(1, &oc->sdf_index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
|
||||
glBindVertexArray(0);
|
||||
} else {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
|
||||
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
|
||||
ERR_FAIL_COND(!oc);
|
||||
oc->cull_mode = p_mode;
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::set_shadow_texture_size(int p_size) {
|
||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||
p_size = nearest_power_of_2_templated(p_size);
|
||||
if (p_size == state.shadow_texture_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_size > config->max_texture_size) {
|
||||
p_size = config->max_texture_size;
|
||||
WARN_PRINT("Attempting to set CanvasItem shadow atlas size to " + itos(p_size) + " which is beyond limit of " + itos(config->max_texture_size) + "supported by hardware.");
|
||||
}
|
||||
|
||||
state.shadow_texture_size = p_size;
|
||||
}
|
||||
|
||||
bool RasterizerCanvasGLES3::free(RID p_rid) {
|
||||
|
@ -1424,6 +1907,9 @@ bool RasterizerCanvasGLES3::free(RID p_rid) {
|
|||
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
|
||||
ERR_FAIL_COND_V(!cl, false);
|
||||
canvas_light_owner.free(p_rid);
|
||||
} else if (occluder_polygon_owner.owns(p_rid)) {
|
||||
occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false);
|
||||
occluder_polygon_owner.free(p_rid);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1623,16 +2109,16 @@ void RasterizerCanvasGLES3::reset_canvas() {
|
|||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 2);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 3);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::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, Projection *p_xform_cache) {
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
|
||||
}
|
||||
|
||||
|
@ -1663,7 +2149,6 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
|
|||
polygon_buffer.resize(buffer_size * sizeof(float));
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, pb.vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, stride * vertex_count * sizeof(float), nullptr, GL_STATIC_DRAW); // TODO may not be necessary
|
||||
uint8_t *r = polygon_buffer.ptrw();
|
||||
float *fptr = reinterpret_cast<float *>(r);
|
||||
uint32_t *uptr = (uint32_t *)r;
|
||||
|
@ -1772,7 +2257,6 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
|
|||
}
|
||||
glGenBuffers(1, &pb.index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, nullptr, GL_STATIC_DRAW); // TODO may not be necessary
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW);
|
||||
pb.count = p_indices.size();
|
||||
}
|
||||
|
@ -2064,6 +2548,9 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
|
|||
data.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
|
||||
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
|
||||
|
||||
shadow_render.shader.initialize();
|
||||
shadow_render.shader_version = shadow_render.shader.version_create();
|
||||
|
||||
{
|
||||
default_canvas_group_shader = material_storage->shader_allocate();
|
||||
material_storage->shader_initialize(default_canvas_group_shader);
|
||||
|
@ -2116,9 +2603,11 @@ void fragment() {
|
|||
}
|
||||
|
||||
RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
|
||||
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
|
||||
singleton = nullptr;
|
||||
|
||||
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
|
||||
material_storage->shaders.canvas_shader.version_free(data.canvas_shader_default_version);
|
||||
shadow_render.shader.version_free(shadow_render.shader_version);
|
||||
material_storage->material_free(default_canvas_group_material);
|
||||
material_storage->shader_free(default_canvas_group_shader);
|
||||
material_storage->material_free(default_clip_children_material);
|
||||
|
@ -2134,6 +2623,15 @@ RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
|
|||
GLES3::TextureStorage::get_singleton()->canvas_texture_free(default_canvas_texture);
|
||||
memdelete_arr(state.instance_data_array);
|
||||
memdelete_arr(state.light_uniforms);
|
||||
|
||||
if (state.shadow_fb != 0) {
|
||||
glDeleteFramebuffers(1, &state.shadow_fb);
|
||||
glDeleteTextures(1, &state.shadow_texture);
|
||||
glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
|
||||
state.shadow_fb = 0;
|
||||
state.shadow_texture = 0;
|
||||
state.shadow_depth_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GLES3_ENABLED
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "storage/texture_storage.h"
|
||||
|
||||
#include "shaders/canvas.glsl.gen.h"
|
||||
#include "shaders/canvas_occlusion.glsl.gen.h"
|
||||
|
||||
class RasterizerSceneGLES3;
|
||||
|
||||
|
@ -102,10 +103,40 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
|
|||
|
||||
struct CanvasLight {
|
||||
RID texture;
|
||||
struct {
|
||||
bool enabled = false;
|
||||
float z_far;
|
||||
float y_offset;
|
||||
Transform2D directional_xform;
|
||||
} shadow;
|
||||
};
|
||||
|
||||
RID_Owner<CanvasLight> canvas_light_owner;
|
||||
|
||||
struct OccluderPolygon {
|
||||
RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
|
||||
int line_point_count = 0;
|
||||
GLuint vertex_buffer = 0;
|
||||
GLuint vertex_array = 0;
|
||||
GLuint index_buffer = 0;
|
||||
|
||||
int sdf_point_count = 0;
|
||||
int sdf_index_count = 0;
|
||||
GLuint sdf_vertex_buffer = 0;
|
||||
GLuint sdf_vertex_array = 0;
|
||||
GLuint sdf_index_buffer = 0;
|
||||
bool sdf_is_lines = false;
|
||||
};
|
||||
|
||||
RID_Owner<OccluderPolygon> occluder_polygon_owner;
|
||||
|
||||
void _update_shadow_atlas();
|
||||
|
||||
struct {
|
||||
CanvasOcclusionShaderGLES3 shader;
|
||||
RID shader_version;
|
||||
} shadow_render;
|
||||
|
||||
struct LightUniform {
|
||||
float matrix[8]; //light to texture coordinate matrix
|
||||
float shadow_matrix[8]; //light to shadow coordinate matrix
|
||||
|
@ -153,9 +184,9 @@ public:
|
|||
};
|
||||
|
||||
struct PolygonBuffers {
|
||||
GLuint vertex_buffer;
|
||||
GLuint vertex_array;
|
||||
GLuint index_buffer;
|
||||
GLuint vertex_buffer = 0;
|
||||
GLuint vertex_array = 0;
|
||||
GLuint index_buffer = 0;
|
||||
int count = 0;
|
||||
bool color_disabled = false;
|
||||
Color color;
|
||||
|
@ -265,6 +296,11 @@ public:
|
|||
|
||||
LightUniform *light_uniforms = nullptr;
|
||||
|
||||
GLuint shadow_texture = 0;
|
||||
GLuint shadow_depth_buffer = 0;
|
||||
GLuint shadow_fb = 0;
|
||||
int shadow_texture_size = 2048;
|
||||
|
||||
bool using_directional_lights = false;
|
||||
|
||||
RID current_tex = RID();
|
||||
|
@ -295,9 +331,6 @@ public:
|
|||
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
||||
|
||||
void reset_canvas();
|
||||
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, Projection *p_xform_cache);
|
||||
|
||||
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override;
|
||||
|
||||
RID light_create() override;
|
||||
void light_set_texture(RID p_rid, RID p_texture) override;
|
||||
|
|
|
@ -208,8 +208,10 @@ protected:
|
|||
spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!spec); // Should never happen
|
||||
ERR_FAIL_COND(!spec->ok); // Should never happen
|
||||
if (!spec || !spec->ok) {
|
||||
WARN_PRINT_ONCE("shader failed to compile, unable to bind shader.");
|
||||
return;
|
||||
}
|
||||
|
||||
glUseProgram(spec->id);
|
||||
current_shader = spec;
|
||||
|
|
|
@ -17,3 +17,5 @@ if "GLES3_GLSL" in env["BUILDERS"]:
|
|||
env.GLES3_GLSL("scene.glsl")
|
||||
env.GLES3_GLSL("sky.glsl")
|
||||
env.GLES3_GLSL("cubemap_filter.glsl")
|
||||
env.GLES3_GLSL("canvas_occlusion.glsl")
|
||||
env.GLES3_GLSL("canvas_sdf.glsl")
|
||||
|
|
|
@ -10,6 +10,7 @@ mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
|
|||
#[specializations]
|
||||
|
||||
DISABLE_LIGHTING = false
|
||||
USE_RGBA_SHADOWS = false
|
||||
|
||||
#[vertex]
|
||||
|
||||
|
@ -213,8 +214,8 @@ void main() {
|
|||
|
||||
#ifndef DISABLE_LIGHTING
|
||||
uniform sampler2D atlas_texture; //texunit:-2
|
||||
uniform sampler2D shadow_atlas_texture; //texunit:-3
|
||||
#endif // DISABLE_LIGHTING
|
||||
//uniform sampler2D shadow_atlas_texture; //texunit:-3
|
||||
uniform sampler2D screen_texture; //texunit:-4
|
||||
uniform sampler2D sdf_texture; //texunit:-5
|
||||
uniform sampler2D normal_texture; //texunit:-6
|
||||
|
@ -245,6 +246,35 @@ layout(std140) uniform MaterialUniforms{
|
|||
#endif
|
||||
|
||||
#GLOBALS
|
||||
|
||||
float vec4_to_float(vec4 p_vec) {
|
||||
return dot(p_vec, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
vec2 screen_uv_to_sdf(vec2 p_uv) {
|
||||
return screen_to_sdf * p_uv;
|
||||
}
|
||||
|
||||
float texture_sdf(vec2 p_sdf) {
|
||||
vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
|
||||
float d = vec4_to_float(texture(sdf_texture, uv));
|
||||
d *= SDF_MAX_LENGTH;
|
||||
return d * tex_to_sdf;
|
||||
}
|
||||
|
||||
vec2 texture_sdf_normal(vec2 p_sdf) {
|
||||
vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
|
||||
|
||||
const float EPSILON = 0.001;
|
||||
return normalize(vec2(
|
||||
vec4_to_float(texture(sdf_texture, uv + vec2(EPSILON, 0.0))) - vec4_to_float(texture(sdf_texture, uv - vec2(EPSILON, 0.0))),
|
||||
vec4_to_float(texture(sdf_texture, uv + vec2(0.0, EPSILON))) - vec4_to_float(texture(sdf_texture, uv - vec2(0.0, EPSILON)))));
|
||||
}
|
||||
|
||||
vec2 sdf_to_screen_uv(vec2 p_sdf) {
|
||||
return p_sdf * sdf_to_screen;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_LIGHTING
|
||||
#ifdef LIGHT_CODE_USED
|
||||
|
||||
|
@ -299,6 +329,70 @@ vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 lig
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_RGBA_SHADOWS
|
||||
|
||||
#define SHADOW_DEPTH(m_uv) (dot(textureLod(shadow_atlas_texture, (m_uv), 0.0), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0)
|
||||
|
||||
#else
|
||||
|
||||
#define SHADOW_DEPTH(m_uv) (textureLod(shadow_atlas_texture, (m_uv), 0.0).r)
|
||||
|
||||
#endif
|
||||
|
||||
#define SHADOW_TEST(m_uv) \
|
||||
{ \
|
||||
highp float sd = SHADOW_DEPTH(m_uv); \
|
||||
shadow += step(sd, shadow_uv.z / shadow_uv.w); \
|
||||
}
|
||||
|
||||
//float distance = length(shadow_pos);
|
||||
vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
vec3 shadow_modulate
|
||||
#endif
|
||||
) {
|
||||
float shadow = 0.0;
|
||||
uint shadow_mode = light_array[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
|
||||
|
||||
if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
|
||||
SHADOW_TEST(shadow_uv.xy);
|
||||
} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
|
||||
vec2 shadow_pixel_size = vec2(light_array[light_base].shadow_pixel_size, 0.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 2.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size);
|
||||
SHADOW_TEST(shadow_uv.xy);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 2.0);
|
||||
shadow /= 5.0;
|
||||
} else { //PCF13
|
||||
vec2 shadow_pixel_size = vec2(light_array[light_base].shadow_pixel_size, 0.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 6.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 5.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 4.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 3.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 2.0);
|
||||
SHADOW_TEST(shadow_uv.xy - shadow_pixel_size);
|
||||
SHADOW_TEST(shadow_uv.xy);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 2.0);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 3.0);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 4.0);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 5.0);
|
||||
SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 6.0);
|
||||
shadow /= 13.0;
|
||||
}
|
||||
|
||||
vec4 shadow_color = unpackUnorm4x8(light_array[light_base].shadow_color);
|
||||
#ifdef LIGHT_CODE_USED
|
||||
shadow_color.rgb *= 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[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
|
||||
|
||||
|
@ -527,6 +621,19 @@ void main() {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
|
||||
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[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[light_base].shadow_y_ofs, shadow_pos.y * light_array[light_base].shadow_zfar_inv, 1.0);
|
||||
|
||||
light_color = light_shadow_compute(light_base, light_color, shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
shadow_modulate.rgb
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
light_blend_compute(light_base, light_color, color.rgb);
|
||||
}
|
||||
|
||||
|
@ -584,6 +691,46 @@ void main() {
|
|||
light_color.a = 0.0;
|
||||
}
|
||||
|
||||
if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
|
||||
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[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.
|
||||
|
||||
vec2 pos_norm = normalize(shadow_pos);
|
||||
vec2 pos_abs = abs(pos_norm);
|
||||
vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
|
||||
vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
|
||||
float tex_ofs;
|
||||
float dist;
|
||||
if (pos_rot.y > 0.0) {
|
||||
if (pos_rot.x > 0.0) {
|
||||
tex_ofs = pos_box.y * 0.125 + 0.125;
|
||||
dist = shadow_pos.x;
|
||||
} else {
|
||||
tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
|
||||
dist = shadow_pos.y;
|
||||
}
|
||||
} else {
|
||||
if (pos_rot.x < 0.0) {
|
||||
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
|
||||
dist = -shadow_pos.x;
|
||||
} else {
|
||||
tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
|
||||
dist = -shadow_pos.y;
|
||||
}
|
||||
}
|
||||
|
||||
dist *= light_array[light_base].shadow_zfar_inv;
|
||||
|
||||
//float distance = length(shadow_pos);
|
||||
vec4 shadow_uv = vec4(tex_ofs, light_array[light_base].shadow_y_ofs, dist, 1.0);
|
||||
|
||||
light_color = light_shadow_compute(light_base, light_color, shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
shadow_modulate.rgb
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
light_blend_compute(light_base, light_color, color.rgb);
|
||||
}
|
||||
#endif
|
||||
|
|
68
drivers/gles3/shaders/canvas_occlusion.glsl
Normal file
68
drivers/gles3/shaders/canvas_occlusion.glsl
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* clang-format off */
|
||||
#[modes]
|
||||
|
||||
mode_sdf =
|
||||
mode_shadow = #define MODE_SHADOW
|
||||
mode_shadow_RGBA = #define MODE_SHADOW \n#define USE_RGBA_SHADOWS
|
||||
|
||||
#[specializations]
|
||||
|
||||
#[vertex]
|
||||
|
||||
layout(location = 0) in vec3 vertex;
|
||||
|
||||
uniform highp mat4 projection;
|
||||
uniform highp vec4 modelview1;
|
||||
uniform highp vec4 modelview2;
|
||||
uniform highp vec2 direction;
|
||||
uniform highp float z_far;
|
||||
|
||||
#ifdef MODE_SHADOW
|
||||
out float depth;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
highp vec4 vtx = vec4(vertex, 1.0) * mat4(modelview1, modelview2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
|
||||
|
||||
#ifdef MODE_SHADOW
|
||||
depth = dot(direction, vtx.xy);
|
||||
#endif
|
||||
gl_Position = projection * vtx;
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
|
||||
uniform highp mat4 projection;
|
||||
uniform highp vec4 modelview1;
|
||||
uniform highp vec4 modelview2;
|
||||
uniform highp vec2 direction;
|
||||
uniform highp float z_far;
|
||||
|
||||
#ifdef MODE_SHADOW
|
||||
in highp float depth;
|
||||
#endif
|
||||
|
||||
#ifdef USE_RGBA_SHADOWS
|
||||
layout(location = 0) out lowp vec4 out_buf;
|
||||
#else
|
||||
layout(location = 0) out highp float out_buf;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
float out_depth = 1.0;
|
||||
|
||||
#ifdef MODE_SHADOW
|
||||
out_depth = depth / z_far;
|
||||
#endif
|
||||
|
||||
#ifdef USE_RGBA_SHADOWS
|
||||
out_depth = clamp(out_depth, -1.0, 1.0);
|
||||
out_depth = out_depth * 0.5 + 0.5;
|
||||
highp vec4 comp = fract(out_depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
|
||||
comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
|
||||
out_buf = comp;
|
||||
#else
|
||||
out_buf = out_depth;
|
||||
#endif
|
||||
}
|
205
drivers/gles3/shaders/canvas_sdf.glsl
Normal file
205
drivers/gles3/shaders/canvas_sdf.glsl
Normal file
|
@ -0,0 +1,205 @@
|
|||
/* clang-format off */
|
||||
#[modes]
|
||||
|
||||
mode_load = #define MODE_LOAD
|
||||
mode_load_shrink = #define MODE_LOAD_SHRINK
|
||||
mode_process = #define MODE_PROCESS
|
||||
mode_store = #define MODE_STORE
|
||||
mode_store_shrink = #define MODE_STORE_SHRINK
|
||||
|
||||
#[specializations]
|
||||
|
||||
#[vertex]
|
||||
|
||||
layout(location = 0) in vec2 vertex_attrib;
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
uniform ivec2 size;
|
||||
uniform int stride;
|
||||
uniform int shift;
|
||||
uniform ivec2 base_size;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
#[fragment]
|
||||
|
||||
#define SDF_MAX_LENGTH 16384.0
|
||||
|
||||
#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK)
|
||||
uniform lowp sampler2D src_pixels;//texunit:0
|
||||
#else
|
||||
uniform highp isampler2D src_process;//texunit:0
|
||||
#endif
|
||||
|
||||
uniform ivec2 size;
|
||||
uniform int stride;
|
||||
uniform int shift;
|
||||
uniform ivec2 base_size;
|
||||
|
||||
#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK) || defined(MODE_PROCESS)
|
||||
layout(location = 0) out ivec4 distance_field;
|
||||
#else
|
||||
layout(location = 0) out vec4 distance_field;
|
||||
#endif
|
||||
|
||||
vec4 float_to_vec4(float p_float) {
|
||||
highp vec4 comp = fract(p_float * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
|
||||
comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
|
||||
return comp;
|
||||
}
|
||||
|
||||
void main() {
|
||||
ivec2 pos = ivec2(gl_FragCoord.xy);
|
||||
|
||||
#ifdef MODE_LOAD
|
||||
|
||||
bool solid = texelFetch(src_pixels, pos, 0).r > 0.5;
|
||||
distance_field = solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef MODE_LOAD_SHRINK
|
||||
|
||||
int s = 1 << shift;
|
||||
ivec2 base = pos << shift;
|
||||
ivec2 center = base + ivec2(shift);
|
||||
|
||||
ivec2 rel = ivec2(32767);
|
||||
float d = 1e20;
|
||||
int found = 0;
|
||||
int solid_found = 0;
|
||||
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, base_size))) {
|
||||
continue;
|
||||
}
|
||||
bool solid = texelFetch(src_pixels, src_pos, 0).r > 0.5;
|
||||
if (solid) {
|
||||
float dist = length(vec2(src_pos - center));
|
||||
if (dist < d) {
|
||||
d = dist;
|
||||
rel = src_pos;
|
||||
}
|
||||
solid_found++;
|
||||
}
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
if (solid_found == found) {
|
||||
//mark solid only if all are solid
|
||||
rel = ivec2(-32767);
|
||||
}
|
||||
|
||||
distance_field = ivec4(rel, 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef MODE_PROCESS
|
||||
|
||||
ivec2 base = pos << shift;
|
||||
ivec2 center = base + ivec2(shift);
|
||||
|
||||
ivec2 rel = texelFetch(src_process, pos, 0).xy;
|
||||
|
||||
bool solid = rel.x < 0;
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
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] * stride;
|
||||
if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, size))) {
|
||||
continue;
|
||||
}
|
||||
ivec2 src_rel = texelFetch(src_process, src_pos, 0).xy;
|
||||
bool src_solid = src_rel.x < 0;
|
||||
if (src_solid) {
|
||||
src_rel = -src_rel - ivec2(1);
|
||||
}
|
||||
|
||||
if (src_solid != solid) {
|
||||
src_rel = ivec2(src_pos << shift); //point to itself if of different type
|
||||
}
|
||||
|
||||
float src_dist = length(vec2(src_rel - center));
|
||||
if (src_dist < dist) {
|
||||
dist = src_dist;
|
||||
rel = src_rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
distance_field = ivec4(rel, 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef MODE_STORE
|
||||
|
||||
ivec2 rel = texelFetch(src_process, pos, 0).xy;
|
||||
|
||||
bool solid = rel.x < 0;
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
float d = length(vec2(rel - pos));
|
||||
|
||||
if (solid) {
|
||||
d = -d;
|
||||
}
|
||||
|
||||
d /= SDF_MAX_LENGTH;
|
||||
d = clamp(d, -1.0, 1.0);
|
||||
distance_field = float_to_vec4(d*0.5+0.5);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_STORE_SHRINK
|
||||
|
||||
ivec2 base = pos << shift;
|
||||
ivec2 center = base + ivec2(shift);
|
||||
|
||||
ivec2 rel = texelFetch(src_process, pos, 0).xy;
|
||||
|
||||
bool solid = rel.x < 0;
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
float d = length(vec2(rel - center));
|
||||
|
||||
if (solid) {
|
||||
d = -d;
|
||||
}
|
||||
d /= SDF_MAX_LENGTH;
|
||||
d = clamp(d, -1.0, 1.0);
|
||||
distance_field = float_to_vec4(d*0.5+0.5);
|
||||
|
||||
#endif
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/* clang-format off */
|
||||
[vertex]
|
||||
|
||||
#ifdef USE_GLES_OVER_GL
|
||||
#define lowp
|
||||
#define mediump
|
||||
#define highp
|
||||
#else
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
#endif
|
||||
|
||||
layout(location = 0) in highp vec3 vertex;
|
||||
|
||||
uniform highp mat4 projection_matrix;
|
||||
/* clang-format on */
|
||||
uniform highp mat4 light_matrix;
|
||||
uniform highp mat4 model_matrix;
|
||||
uniform highp float distance_norm;
|
||||
|
||||
out highp vec4 position_interp;
|
||||
|
||||
void main() {
|
||||
gl_Position = projection_matrix * (light_matrix * (model_matrix * vec4(vertex, 1.0)));
|
||||
position_interp = gl_Position;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
[fragment]
|
||||
|
||||
#ifdef USE_GLES_OVER_GL
|
||||
#define lowp
|
||||
#define mediump
|
||||
#define highp
|
||||
#else
|
||||
#if defined(USE_HIGHP_PRECISION)
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
#else
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
in highp vec4 position_interp;
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias
|
||||
|
||||
#ifdef USE_RGBA_SHADOWS
|
||||
|
||||
highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
|
||||
comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
|
||||
frag_color = comp;
|
||||
#else
|
||||
|
||||
frag_color = vec4(depth);
|
||||
#endif
|
||||
}
|
|
@ -71,7 +71,7 @@ Config::Config() {
|
|||
s3tc_supported = true;
|
||||
rgtc_supported = true; //RGTC - core since OpenGL version 3.0
|
||||
#else
|
||||
float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float");
|
||||
float_texture_supported = extensions.has("GL_EXT_color_buffer_float");
|
||||
etc2_supported = true;
|
||||
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
|
||||
// Some Android devices report support for S3TC but we don't expect that and don't export the textures.
|
||||
|
@ -84,24 +84,14 @@ Config::Config() {
|
|||
rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
|
||||
#endif
|
||||
|
||||
#ifdef GLES_OVER_GL
|
||||
use_rgba_2d_shadows = false;
|
||||
#else
|
||||
use_rgba_2d_shadows = !(float_texture_supported && extensions.has("GL_EXT_texture_rg"));
|
||||
#endif
|
||||
|
||||
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
|
||||
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &max_viewport_size);
|
||||
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
|
||||
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_offset_alignment);
|
||||
|
||||
// the use skeleton software path should be used if either float texture is not supported,
|
||||
// OR max_vertex_texture_image_units is zero
|
||||
use_skeleton_software = (float_texture_supported == false) || (max_vertex_texture_image_units == 0);
|
||||
|
||||
support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic");
|
||||
if (support_anisotropic_filter) {
|
||||
glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level);
|
||||
|
|
|
@ -56,15 +56,13 @@ private:
|
|||
|
||||
public:
|
||||
bool use_nearest_mip_filter = false;
|
||||
bool use_skeleton_software = false;
|
||||
bool use_depth_prepass = true;
|
||||
bool use_rgba_2d_shadows = false;
|
||||
|
||||
int max_vertex_texture_image_units = 0;
|
||||
int max_texture_image_units = 0;
|
||||
int max_texture_size = 0;
|
||||
int max_viewport_size[2] = { 0, 0 };
|
||||
int max_uniform_buffer_size = 0;
|
||||
int max_viewport_size = 0;
|
||||
int max_renderable_elements = 0;
|
||||
int max_renderable_lights = 0;
|
||||
int max_lights_per_object = 0;
|
||||
|
|
|
@ -207,6 +207,11 @@ TextureStorage::TextureStorage() {
|
|||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
{
|
||||
sdf_shader.shader.initialize();
|
||||
sdf_shader.shader_version = sdf_shader.shader.version_create();
|
||||
}
|
||||
|
||||
#ifdef GLES_OVER_GL
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
#endif
|
||||
|
@ -222,6 +227,7 @@ TextureStorage::~TextureStorage() {
|
|||
texture_atlas.texture = 0;
|
||||
glDeleteFramebuffers(1, &texture_atlas.framebuffer);
|
||||
texture_atlas.framebuffer = 0;
|
||||
sdf_shader.shader.version_free(sdf_shader.shader_version);
|
||||
}
|
||||
|
||||
//TODO, move back to storage
|
||||
|
@ -276,55 +282,6 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS:
|
|||
ct->texture_repeat = p_repeat;
|
||||
}
|
||||
|
||||
/* CANVAS SHADOW */
|
||||
|
||||
RID TextureStorage::canvas_light_shadow_buffer_create(int p_width) {
|
||||
Config *config = Config::get_singleton();
|
||||
CanvasLightShadow *cls = memnew(CanvasLightShadow);
|
||||
|
||||
if (p_width > config->max_texture_size) {
|
||||
p_width = config->max_texture_size;
|
||||
}
|
||||
|
||||
cls->size = p_width;
|
||||
cls->height = 16;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glGenFramebuffers(1, &cls->fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
|
||||
|
||||
glGenRenderbuffers(1, &cls->depth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, cls->depth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth);
|
||||
|
||||
glGenTextures(1, &cls->distance);
|
||||
glBindTexture(GL_TEXTURE_2D, cls->distance);
|
||||
if (config->use_rgba_2d_shadows) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
//printf("errnum: %x\n",status);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
memdelete(cls);
|
||||
ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
|
||||
}
|
||||
|
||||
return canvas_light_shadow_owner.make_rid(cls);
|
||||
}
|
||||
|
||||
/* Texture API */
|
||||
|
||||
Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const {
|
||||
|
@ -1599,6 +1556,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
|
|||
rt->backbuffer = 0;
|
||||
rt->backbuffer_fbo = 0;
|
||||
}
|
||||
_render_target_clear_sdf(rt);
|
||||
}
|
||||
|
||||
RID TextureStorage::render_target_create() {
|
||||
|
@ -1784,13 +1742,271 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
|
|||
}
|
||||
|
||||
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
|
||||
RenderTarget *rt = render_target_owner.get_or_null(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 TextureStorage::_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 TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
|
||||
return Rect2i();
|
||||
const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||
ERR_FAIL_COND_V(!rt, Rect2i());
|
||||
|
||||
return _render_target_get_sdf_rect(rt);
|
||||
}
|
||||
|
||||
void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
|
||||
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||
ERR_FAIL_COND(!rt);
|
||||
|
||||
rt->sdf_enabled = p_enabled;
|
||||
}
|
||||
|
||||
bool TextureStorage::render_target_is_sdf_enabled(RID p_render_target) const {
|
||||
const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||
ERR_FAIL_COND_V(!rt, false);
|
||||
|
||||
return rt->sdf_enabled;
|
||||
}
|
||||
|
||||
GLuint TextureStorage::render_target_get_sdf_texture(RID p_render_target) {
|
||||
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||
ERR_FAIL_COND_V(!rt, 0);
|
||||
if (rt->sdf_texture_read == 0) {
|
||||
Texture *texture = texture_owner.get_or_null(default_gl_textures[DEFAULT_GL_TEXTURE_BLACK]);
|
||||
return texture->tex_id;
|
||||
}
|
||||
|
||||
return rt->sdf_texture_read;
|
||||
}
|
||||
|
||||
void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
|
||||
ERR_FAIL_COND(rt->sdf_texture_write_fb != 0);
|
||||
|
||||
Size2i size = _render_target_get_sdf_rect(rt).size;
|
||||
|
||||
glGenTextures(1, &rt->sdf_texture_write);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size.width, size.height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glGenFramebuffers(1, &rt->sdf_texture_write_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, rt->sdf_texture_write_fb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_write, 0);
|
||||
|
||||
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);
|
||||
|
||||
glGenTextures(2, rt->sdf_texture_process);
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[0]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_SHORT, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[1]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_SHORT, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glGenTextures(1, &rt->sdf_texture_read);
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_read);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->process_size.width, rt->process_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
void TextureStorage::_render_target_clear_sdf(RenderTarget *rt) {
|
||||
if (rt->sdf_texture_write_fb != 0) {
|
||||
glDeleteTextures(1, &rt->sdf_texture_read);
|
||||
glDeleteTextures(1, &rt->sdf_texture_write);
|
||||
glDeleteTextures(2, rt->sdf_texture_process);
|
||||
glDeleteFramebuffers(1, &rt->sdf_texture_write_fb);
|
||||
rt->sdf_texture_read = 0;
|
||||
rt->sdf_texture_write = 0;
|
||||
rt->sdf_texture_process[0] = 0;
|
||||
rt->sdf_texture_process[1] = 0;
|
||||
rt->sdf_texture_write_fb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint TextureStorage::render_target_get_sdf_framebuffer(RID p_render_target) {
|
||||
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||
ERR_FAIL_COND_V(!rt, 0);
|
||||
|
||||
if (rt->sdf_texture_write_fb == 0) {
|
||||
_render_target_allocate_sdf(rt);
|
||||
}
|
||||
|
||||
return rt->sdf_texture_write_fb;
|
||||
}
|
||||
void TextureStorage::render_target_sdf_process(RID p_render_target) {
|
||||
CopyEffects *copy_effects = CopyEffects::get_singleton();
|
||||
|
||||
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||
ERR_FAIL_COND(!rt);
|
||||
ERR_FAIL_COND(rt->sdf_texture_write_fb == 0);
|
||||
|
||||
Rect2i r = _render_target_get_sdf_rect(rt);
|
||||
|
||||
Size2i size = r.size;
|
||||
int32_t shift = 0;
|
||||
|
||||
bool shrink = false;
|
||||
|
||||
switch (rt->sdf_scale) {
|
||||
case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
|
||||
size[0] >>= 1;
|
||||
size[1] >>= 1;
|
||||
shift = 1;
|
||||
shrink = true;
|
||||
} break;
|
||||
case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
|
||||
size[0] >>= 2;
|
||||
size[1] >>= 2;
|
||||
shift = 2;
|
||||
shrink = true;
|
||||
} break;
|
||||
default: {
|
||||
};
|
||||
}
|
||||
|
||||
GLuint temp_fb;
|
||||
glGenFramebuffers(1, &temp_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, temp_fb);
|
||||
|
||||
// Load
|
||||
CanvasSdfShaderGLES3::ShaderVariant variant = shrink ? CanvasSdfShaderGLES3::MODE_LOAD_SHRINK : CanvasSdfShaderGLES3::MODE_LOAD;
|
||||
sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, 0, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_process[0], 0);
|
||||
glViewport(0, 0, size.width, size.height);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(0, 0, size.width, size.height);
|
||||
|
||||
copy_effects->draw_screen_triangle();
|
||||
|
||||
// Process
|
||||
|
||||
int stride = nearest_power_of_2_templated(MAX(size.width, size.height) / 2);
|
||||
|
||||
variant = CanvasSdfShaderGLES3::MODE_PROCESS;
|
||||
sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
|
||||
|
||||
bool swap = false;
|
||||
|
||||
//jumpflood
|
||||
while (stride > 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 0 : 1], 0);
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 1 : 0]);
|
||||
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
|
||||
|
||||
copy_effects->draw_screen_triangle();
|
||||
|
||||
stride /= 2;
|
||||
swap = !swap;
|
||||
}
|
||||
|
||||
// Store
|
||||
variant = shrink ? CanvasSdfShaderGLES3::MODE_STORE_SHRINK : CanvasSdfShaderGLES3::MODE_STORE;
|
||||
sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_read, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 1 : 0]);
|
||||
|
||||
copy_effects->draw_screen_triangle();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
|
||||
glDeleteFramebuffers(1, &temp_fb);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include "servers/rendering/renderer_compositor.h"
|
||||
#include "servers/rendering/storage/texture_storage.h"
|
||||
|
||||
#include "../shaders/canvas_sdf.glsl.gen.h"
|
||||
|
||||
// This must come first to avoid windows.h mess
|
||||
#include "platform_config.h"
|
||||
#ifndef OPENGL_INCLUDE_H
|
||||
|
@ -84,18 +86,8 @@ namespace GLES3 {
|
|||
|
||||
#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
|
||||
|
||||
#ifdef GLES_OVER_GL
|
||||
#define _GL_HALF_FLOAT_OES 0x140B
|
||||
#else
|
||||
#define _GL_HALF_FLOAT_OES 0x8D61
|
||||
#endif
|
||||
|
||||
#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
|
||||
|
||||
#define _RED_OES 0x1903
|
||||
|
||||
#define _DEPTH_COMPONENT24_OES 0x81A6
|
||||
|
||||
#ifndef GLES_OVER_GL
|
||||
#define glClearDepth glClearDepthf
|
||||
#endif //!GLES_OVER_GL
|
||||
|
@ -128,17 +120,6 @@ struct CanvasTexture {
|
|||
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
|
||||
};
|
||||
|
||||
/* CANVAS SHADOW */
|
||||
|
||||
struct CanvasLightShadow {
|
||||
RID self;
|
||||
int size;
|
||||
int height;
|
||||
GLuint fbo;
|
||||
GLuint depth;
|
||||
GLuint distance; //for older devices
|
||||
};
|
||||
|
||||
struct RenderTarget;
|
||||
|
||||
struct Texture {
|
||||
|
@ -337,6 +318,15 @@ struct RenderTarget {
|
|||
GLuint color_type = GL_UNSIGNED_BYTE;
|
||||
Image::Format image_format = Image::FORMAT_RGBA8;
|
||||
|
||||
GLuint sdf_texture_write = 0;
|
||||
GLuint sdf_texture_write_fb = 0;
|
||||
GLuint sdf_texture_process[2] = { 0, 0 };
|
||||
GLuint sdf_texture_read = 0;
|
||||
RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
|
||||
RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
|
||||
Size2i process_size;
|
||||
bool sdf_enabled = false;
|
||||
|
||||
bool is_transparent = false;
|
||||
bool direct_to_screen = false;
|
||||
|
||||
|
@ -362,10 +352,6 @@ private:
|
|||
|
||||
RID_Owner<CanvasTexture, true> canvas_texture_owner;
|
||||
|
||||
/* CANVAS SHADOW */
|
||||
|
||||
RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner;
|
||||
|
||||
/* Texture API */
|
||||
|
||||
mutable RID_Owner<Texture> texture_owner;
|
||||
|
@ -411,6 +397,14 @@ private:
|
|||
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 {
|
||||
CanvasSdfShaderGLES3 shader;
|
||||
RID shader_version;
|
||||
} sdf_shader;
|
||||
|
||||
public:
|
||||
static TextureStorage *get_singleton();
|
||||
|
@ -437,10 +431,6 @@ public:
|
|||
virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
|
||||
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;
|
||||
|
||||
/* CANVAS SHADOW */
|
||||
|
||||
RID canvas_light_shadow_buffer_create(int p_width);
|
||||
|
||||
/* Texture API */
|
||||
|
||||
Texture *get_texture(RID p_rid) {
|
||||
|
@ -586,9 +576,13 @@ public:
|
|||
void render_target_disable_clear_request(RID p_render_target) override;
|
||||
void render_target_do_clear_request(RID p_render_target) override;
|
||||
|
||||
void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
|
||||
Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
|
||||
void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
|
||||
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
|
||||
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
|
||||
GLuint render_target_get_sdf_texture(RID p_render_target);
|
||||
GLuint render_target_get_sdf_framebuffer(RID p_render_target);
|
||||
void render_target_sdf_process(RID p_render_target);
|
||||
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
|
||||
bool render_target_is_sdf_enabled(RID p_render_target) const;
|
||||
|
||||
void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
|
||||
void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
|
||||
|
|
|
@ -362,7 +362,7 @@ Size2i Utilities::get_maximum_viewport_size() const {
|
|||
return Size2i();
|
||||
}
|
||||
|
||||
return Size2i(config->max_viewport_size, config->max_viewport_size);
|
||||
return Size2i(config->max_viewport_size[0], config->max_viewport_size[1]);
|
||||
}
|
||||
|
||||
#endif // GLES3_ENABLED
|
||||
|
|
|
@ -39,7 +39,6 @@ public:
|
|||
void free_polygon(PolygonID p_polygon) override {}
|
||||
|
||||
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_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) override {}
|
||||
void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override {}
|
||||
|
||||
RID light_create() override { return RID(); }
|
||||
void light_set_texture(RID p_rid, RID p_texture) override {}
|
||||
|
|
|
@ -476,7 +476,6 @@ public:
|
|||
};
|
||||
|
||||
virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_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) = 0;
|
||||
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
|
||||
|
||||
struct LightOccluderInstance {
|
||||
bool enabled;
|
||||
|
|
|
@ -1914,11 +1914,12 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve
|
|||
}
|
||||
}
|
||||
|
||||
//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
|
||||
//if same buffer len is being set, just use buffer_update to avoid a pipeline flush
|
||||
|
||||
if (oc->vertex_array.is_null()) {
|
||||
//create from scratch
|
||||
//vertices
|
||||
// TODO: geometry is always of length lc * 6 * sizeof(float), so in doubles builds this will receive half the data it needs
|
||||
oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry);
|
||||
|
||||
Vector<RID> buffer;
|
||||
|
|
|
@ -459,8 +459,6 @@ public:
|
|||
|
||||
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) {}
|
||||
|
||||
virtual void set_shadow_texture_size(int p_size);
|
||||
|
||||
void set_time(double p_time);
|
||||
|
|
Loading…
Reference in a new issue