Add GPUParticles to the OpenGL3 renderer.

This includes collision (2D SDF, Box, Sphere, Heightmap),
attraction (Box, Sphere), and all sorting modes.

This does not include 3D SDF collisions, trails, or
manual emission.
This commit is contained in:
clayjohn 2022-11-07 22:40:03 -08:00
parent 98e0d59952
commit 9ce57050a5
31 changed files with 2906 additions and 317 deletions

View File

@ -115,13 +115,21 @@ CopyEffects::~CopyEffects() {
} }
void CopyEffects::copy_to_rect(const Rect2 &p_rect) { void CopyEffects::copy_to_rect(const Rect2 &p_rect) {
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION); bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
if (!success) {
return;
}
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); 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);
draw_screen_quad(); draw_screen_quad();
} }
void CopyEffects::copy_screen() { void CopyEffects::copy_screen() {
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT); bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
if (!success) {
return;
}
draw_screen_triangle(); draw_screen_triangle();
} }
@ -151,7 +159,11 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con
} }
void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) { void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR); bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
if (!success) {
return;
}
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::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); copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
draw_screen_quad(); draw_screen_quad();

View File

@ -41,6 +41,7 @@
#include "storage/config.h" #include "storage/config.h"
#include "storage/material_storage.h" #include "storage/material_storage.h"
#include "storage/mesh_storage.h" #include "storage/mesh_storage.h"
#include "storage/particles_storage.h"
#include "storage/texture_storage.h" #include "storage/texture_storage.h"
void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
@ -578,7 +579,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX; GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
_record_item_commands(ci, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken); _record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken);
} }
if (index == 0) { if (index == 0) {
@ -623,7 +624,10 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
uint64_t specialization = 0; uint64_t specialization = 0;
specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled); specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1; specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
_bind_material(material_data, variant, specialization); bool success = _bind_material(material_data, variant, specialization);
if (!success) {
continue;
}
GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode; GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
@ -707,7 +711,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
r_last_index += index; r_last_index += index;
} }
void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken) { void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken) {
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter; RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) { if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
@ -1064,15 +1068,45 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, const Tran
state.canvas_instance_batches[state.current_batch_index].tex = m->texture; state.canvas_instance_batches[state.current_batch_index].tex = m->texture;
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, state.instance_data_array[r_index].world); _update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, state.instance_data_array[r_index].world);
modulate = m->modulate; modulate = m->modulate;
} else if (c->type == Item::Command::TYPE_MULTIMESH) { } else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c); const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
state.canvas_instance_batches[state.current_batch_index].tex = mm->texture; state.canvas_instance_batches[state.current_batch_index].tex = mm->texture;
uint32_t instance_count = GLES3::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(mm->multimesh); state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
if (instance_count > 1) {
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
}
} else if (c->type == Item::Command::TYPE_PARTICLES) { } else if (c->type == Item::Command::TYPE_PARTICLES) {
WARN_PRINT_ONCE("Particles not supported yet, sorry :("); GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
RID particles = pt->particles;
state.canvas_instance_batches[state.current_batch_index].tex = pt->texture;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
bool local_coords = particles_storage->particles_is_using_local_coords(particles);
if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target)) {
// Pass collision information.
Transform2D xform;
if (local_coords) {
xform = p_item->final_transform;
} else {
xform = p_canvas_transform_inverse;
}
GLuint sdf_texture = texture_storage->render_target_get_sdf_texture(p_render_target);
Rect2 to_screen;
{
Rect2 sdf_rect = texture_storage->render_target_get_sdf_rect(p_render_target);
to_screen.size = Vector2(1.0 / sdf_rect.size.width, 1.0 / sdf_rect.size.height);
to_screen.position = -sdf_rect.position * to_screen.size;
}
particles_storage->particles_set_canvas_sdf_collision(pt->particles, true, xform, to_screen, sdf_texture);
} else {
particles_storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), 0);
}
} }
state.canvas_instance_batches[state.current_batch_index].command = c; state.canvas_instance_batches[state.current_batch_index].command = c;
@ -1209,20 +1243,21 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
case Item::Command::TYPE_MULTIMESH: case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: { case Item::Command::TYPE_PARTICLES: {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton(); GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
RID mesh; RID mesh;
RID mesh_instance; RID mesh_instance;
RID texture;
uint32_t instance_count = 1; uint32_t instance_count = 1;
GLuint multimesh_buffer = 0; GLuint instance_buffer = 0;
uint32_t multimesh_stride = 0; uint32_t instance_stride = 0;
uint32_t multimesh_color_offset = 0; uint32_t instance_color_offset = 0;
bool multimesh_uses_color = false; bool instance_uses_color = false;
bool multimesh_uses_custom_data = false; bool instance_uses_custom_data = false;
if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MESH) { if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(state.canvas_instance_batches[p_index].command); const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(state.canvas_instance_batches[p_index].command);
mesh = m->mesh; mesh = m->mesh;
mesh_instance = m->mesh_instance; mesh_instance = m->mesh_instance;
} else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MULTIMESH) { } else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(state.canvas_instance_batches[p_index].command); const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(state.canvas_instance_batches[p_index].command);
RID multimesh = mm->multimesh; RID multimesh = mm->multimesh;
@ -1238,13 +1273,41 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
break; break;
} }
multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh); instance_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
multimesh_stride = mesh_storage->multimesh_get_stride(multimesh); instance_stride = mesh_storage->multimesh_get_stride(multimesh);
multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh); instance_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh); instance_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh); instance_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
} else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_PARTICLES) { } else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_PARTICLES) {
// Do nothing for now. const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(state.canvas_instance_batches[p_index].command);
RID particles = pt->particles;
mesh = particles_storage->particles_get_draw_pass_mesh(particles, 0);
ERR_BREAK(particles_storage->particles_get_mode(particles) != RS::PARTICLES_MODE_2D);
particles_storage->particles_request_process(particles);
if (particles_storage->particles_is_inactive(particles)) {
break;
}
RenderingServerDefault::redraw_request(); // Active particles means redraw request.
int dpc = particles_storage->particles_get_draw_passes(particles);
if (dpc == 0) {
break; // Nothing to draw.
}
instance_count = particles_storage->particles_get_amount(particles);
instance_buffer = particles_storage->particles_get_gl_buffer(particles);
instance_stride = 12; // 8 bytes for instance transform and 4 bytes for packed color and custom.
instance_color_offset = 8; // 8 bytes for instance transform.
instance_uses_color = true;
instance_uses_custom_data = true;
}
if (instance_buffer == 0) {
break;
} }
ERR_FAIL_COND(mesh.is_null()); ERR_FAIL_COND(mesh.is_null());
@ -1277,17 +1340,17 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
if (instance_count > 1) { if (instance_count > 1) {
// Bind instance buffers. // Bind instance buffers.
glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer); glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0)); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
glVertexAttribDivisor(1, 1); glVertexAttribDivisor(1, 1);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
glVertexAttribDivisor(2, 1); glVertexAttribDivisor(2, 1);
if (multimesh_uses_color || multimesh_uses_custom_data) { if (instance_uses_color || instance_uses_custom_data) {
glEnableVertexAttribArray(5); glEnableVertexAttribArray(5);
glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float))); glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(instance_color_offset * sizeof(float)));
glVertexAttribDivisor(5, 1); glVertexAttribDivisor(5, 1);
} }
} }
@ -1361,17 +1424,17 @@ void RasterizerCanvasGLES3::_new_batch(bool &r_batch_broken, uint32_t &r_index)
_align_instance_data_buffer(r_index); _align_instance_data_buffer(r_index);
} }
void RasterizerCanvasGLES3::_bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization) { bool RasterizerCanvasGLES3::_bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization) {
if (p_material_data) { if (p_material_data) {
if (p_material_data->shader_data->version.is_valid() && p_material_data->shader_data->valid) { if (p_material_data->shader_data->version.is_valid() && p_material_data->shader_data->valid) {
// Bind uniform buffer and textures // Bind uniform buffer and textures
p_material_data->bind_uniforms(); p_material_data->bind_uniforms();
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(p_material_data->shader_data->version, p_variant, p_specialization); return GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(p_material_data->shader_data->version, p_variant, p_specialization);
} else { } else {
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization); return GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization);
} }
} else { } else {
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization); return GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization);
} }
} }
@ -1435,7 +1498,10 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c
RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA; 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); bool success = shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
if (!success) {
return;
}
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
@ -1553,7 +1619,10 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha
RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA; 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); bool success = shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
if (!success) {
return;
}
Projection projection; Projection projection;
projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
@ -1685,7 +1754,10 @@ void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstanc
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
CanvasOcclusionShaderGLES3::ShaderVariant variant = CanvasOcclusionShaderGLES3::MODE_SDF; CanvasOcclusionShaderGLES3::ShaderVariant variant = CanvasOcclusionShaderGLES3::MODE_SDF;
shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant); bool success = shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
if (!success) {
return;
}
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, Projection(), 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::DIRECTION, 0.0, 0.0, shadow_render.shader_version, variant);
@ -2555,7 +2627,6 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines); GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines);
data.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create(); 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.initialize();
shadow_render.shader_version = shadow_render.shader.version_create(); shadow_render.shader_version = shadow_render.shader.version_create();

View File

@ -352,9 +352,9 @@ 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_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_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 _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool p_to_backbuffer = false); void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool p_to_backbuffer = false);
void _record_item_commands(const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch); void _record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch);
void _render_batch(Light *p_lights, uint32_t p_index); void _render_batch(Light *p_lights, uint32_t p_index);
void _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization); bool _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization);
void _new_batch(bool &r_batch_broken, uint32_t &r_index); void _new_batch(bool &r_batch_broken, uint32_t &r_index);
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken); void _add_to_batch(uint32_t &r_index, bool &r_batch_broken);
void _allocate_instance_data_buffer(); void _allocate_instance_data_buffer();

View File

@ -35,6 +35,7 @@
#include "servers/rendering/rendering_server_globals.h" #include "servers/rendering/rendering_server_globals.h"
#include "storage/config.h" #include "storage/config.h"
#include "storage/mesh_storage.h" #include "storage/mesh_storage.h"
#include "storage/particles_storage.h"
#include "storage/texture_storage.h" #include "storage/texture_storage.h"
#ifdef GLES3_ENABLED #ifdef GLES3_ENABLED
@ -50,6 +51,9 @@ RenderGeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_bas
ginstance->data->base = p_base; ginstance->data->base = p_base;
ginstance->data->base_type = type; ginstance->data->base_type = type;
ginstance->data->dependency_tracker.userdata = ginstance;
ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed;
ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted;
ginstance->_mark_dirty(); ginstance->_mark_dirty();
@ -314,6 +318,8 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface(GeometryInstanceGLES3
void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_geometry_instance) { void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_geometry_instance) {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton(); GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance); GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
if (ginstance->data->dirty_dependencies) { if (ginstance->data->dirty_dependencies) {
@ -361,6 +367,26 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
} break; } break;
case RS::INSTANCE_PARTICLES: { case RS::INSTANCE_PARTICLES: {
int draw_passes = particles_storage->particles_get_draw_passes(ginstance->data->base);
for (int j = 0; j < draw_passes; j++) {
RID mesh = particles_storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
if (!mesh.is_valid()) {
continue;
}
const RID *materials = nullptr;
uint32_t surface_count;
materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
if (materials) {
for (uint32_t k = 0; k < surface_count; k++) {
_geometry_instance_add_surface(ginstance, k, materials[k], mesh);
}
}
}
ginstance->instance_count = particles_storage->particles_get_amount(ginstance->data->base);
} break; } break;
default: { default: {
@ -382,9 +408,17 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
} }
//ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_globals.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_PARTICLES;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
if (!particles_storage->particles_is_using_local_coords(ginstance->data->base)) {
store_transform = false;
}
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) { } else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
} }
@ -751,12 +785,16 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
sky_transform.invert(); sky_transform.invert();
sky_transform = p_transform.basis * sky_transform; sky_transform = p_transform.basis * sky_transform;
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND); bool success = material_storage->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND); if (!success) {
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.columns[2][0], camera.columns[0][0], camera.columns[2][1], camera.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND); return;
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND); }
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND); material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.columns[2][0], camera.columns[0][0], camera.columns[2][1], camera.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
glBindVertexArray(sky_globals.screen_triangle_array); glBindVertexArray(sky_globals.screen_triangle_array);
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
@ -850,12 +888,15 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
correction.columns[1][1] = -1.0; correction.columns[1][1] = -1.0;
cm = correction * cm; cm = correction * cm;
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); bool success = material_storage->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
if (!success) {
return;
}
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.columns[2][0], cm.columns[0][0], cm.columns[2][1], cm.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.columns[2][0], cm.columns[0][0], cm.columns[2][1], cm.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glBindVertexArray(sky_globals.screen_triangle_array); glBindVertexArray(sky_globals.screen_triangle_array);
@ -864,7 +905,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, local_view, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, local_view, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, sky->raw_radiance, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, sky->raw_radiance, 0);
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
} }
@ -945,7 +986,10 @@ void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
glViewport(0, 0, size, size); glViewport(0, 0, size, size);
glBindVertexArray(sky_globals.screen_triangle_array); glBindVertexArray(sky_globals.screen_triangle_array);
material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, mode); bool success = material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, mode);
if (!success) {
return;
}
if (p_base_layer > 0) { if (p_base_layer > 0) {
const uint32_t sample_counts[4] = { 1, sky_globals.ggx_samples / 4, sky_globals.ggx_samples / 2, sky_globals.ggx_samples }; const uint32_t sample_counts[4] = { 1, sky_globals.ggx_samples / 4, sky_globals.ggx_samples / 2, sky_globals.ggx_samples };
@ -1851,8 +1895,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glColorMask(0, 0, 0, 0); glColorMask(0, 0, 0, 0);
glClearDepth(1.0f); glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
uint32_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
SceneShaderGLES3::DISABLE_LIGHT_SPOT;
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, 0, use_wireframe); RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant, use_wireframe);
_render_list_template<PASS_MODE_DEPTH>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size()); _render_list_template<PASS_MODE_DEPTH>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
glColorMask(1, 1, 1, 1); glColorMask(1, 1, 1, 1);
@ -1894,11 +1941,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
{ {
// Specialization Constants that apply for entire rendering pass. // Specialization Constants that apply for entire rendering pass.
if (render_data.directional_light_count == 0) { if (render_data.directional_light_count == 0) {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS; spec_constant_base_flags |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
} }
if (render_data.environment.is_null() || (render_data.environment.is_valid() && !environment_get_fog_enabled(render_data.environment))) { if (render_data.environment.is_null() || (render_data.environment.is_valid() && !environment_get_fog_enabled(render_data.environment))) {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG; spec_constant_base_flags |= SceneShaderGLES3::DISABLE_FOG;
} }
} }
// Render Opaque Objects. // Render Opaque Objects.
@ -1947,6 +1994,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
template <PassMode p_pass_mode> template <PassMode p_pass_mode>
void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) { void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton(); GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton(); GLES3::Config *config = GLES3::Config::get_singleton();
@ -1960,11 +2008,10 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR; SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR;
SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized
// @todo Get this from p_params->spec_constant_base_flags instead of hardcoding it. uint32_t base_spec_constants = p_params->spec_constant_base_flags;
uint32_t base_spec_constants = 0;
if (p_render_data->view_count > 1) { if (p_render_data->view_count > 1) {
base_spec_constants |= 1 << SPEC_CONSTANT_USE_MULTIVIEW; base_spec_constants |= SceneShaderGLES3::USE_MULTIVIEW;
} }
switch (p_pass_mode) { switch (p_pass_mode) {
@ -1987,7 +2034,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
Sky *sky = sky_owner.get_or_null(environment_get_sky(p_render_data->environment)); Sky *sky = sky_owner.get_or_null(environment_get_sky(p_render_data->environment));
if (sky && sky->radiance != 0) { if (sky && sky->radiance != 0) {
texture_to_bind = sky->radiance; texture_to_bind = sky->radiance;
// base_spec_constant |= USE_RADIANCE_MAP; base_spec_constants |= SceneShaderGLES3::USE_RADIANCE_MAP;
} }
glBindTexture(GL_TEXTURE_CUBE_MAP, texture_to_bind); glBindTexture(GL_TEXTURE_CUBE_MAP, texture_to_bind);
} }
@ -2157,7 +2204,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
} }
bool use_index_buffer = index_array_gl != 0; bool use_index_buffer = index_array_gl != 0;
if (prev_index_array_gl != index_array_gl) { if (prev_index_array_gl != index_array_gl || prev_vertex_array_gl != vertex_array_gl) {
if (index_array_gl != 0) { if (index_array_gl != 0) {
// Bind index each time so we can use LODs // Bind index each time so we can use LODs
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
@ -2177,11 +2224,16 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
SceneShaderGLES3::ShaderVariant instance_variant = shader_variant; SceneShaderGLES3::ShaderVariant instance_variant = shader_variant;
if (inst->instance_count > 0) { if (inst->instance_count > 0) {
// Will need to use instancing to draw (either MultiMesh or Particles).
instance_variant = SceneShaderGLES3::ShaderVariant(1 + int(shader_variant)); instance_variant = SceneShaderGLES3::ShaderVariant(1 + int(shader_variant));
} }
if (prev_shader != shader || prev_variant != instance_variant) { if (prev_shader != shader || prev_variant != instance_variant) {
material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, base_spec_constants); bool success = material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, base_spec_constants);
if (!success) {
continue;
}
float opaque_prepass_threshold = 0.0; float opaque_prepass_threshold = 0.0;
if constexpr (p_pass_mode == PASS_MODE_DEPTH) { if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
opaque_prepass_threshold = 0.99; opaque_prepass_threshold = 0.99;
@ -2213,25 +2265,42 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, base_spec_constants); material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, base_spec_constants);
if (inst->instance_count > 0) { if (inst->instance_count > 0) {
// Using MultiMesh. // Using MultiMesh or Particles.
// Bind instance buffers. // Bind instance buffers.
GLuint multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(inst->data->base); GLuint instance_buffer = 0;
glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer); uint32_t stride = 0;
uint32_t multimesh_stride = mesh_storage->multimesh_get_stride(inst->data->base); if (inst->flags_cache & INSTANCE_DATA_FLAG_PARTICLES) {
instance_buffer = particles_storage->particles_get_gl_buffer(inst->data->base);
stride = 16; // 12 bytes for instance transform and 4 bytes for packed color and custom.
} else {
instance_buffer = mesh_storage->multimesh_get_gl_buffer(inst->data->base);
stride = mesh_storage->multimesh_get_stride(inst->data->base);
}
if (instance_buffer == 0) {
// Instance buffer not initialized yet. Skip rendering for now.
continue;
}
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
glEnableVertexAttribArray(12); glEnableVertexAttribArray(12);
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0)); glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
glVertexAttribDivisor(12, 1); glVertexAttribDivisor(12, 1);
glEnableVertexAttribArray(13); glEnableVertexAttribArray(13);
glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4)); glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4));
glVertexAttribDivisor(13, 1); glVertexAttribDivisor(13, 1);
glEnableVertexAttribArray(14); if (!(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D)) {
glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 8)); glEnableVertexAttribArray(14);
glVertexAttribDivisor(14, 1); glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 8));
glVertexAttribDivisor(14, 1);
}
if (mesh_storage->multimesh_uses_colors(inst->data->base) || mesh_storage->multimesh_uses_custom_data(inst->data->base)) { if ((inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR) || (inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA)) {
uint32_t color_custom_offset = inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D ? 8 : 12;
glEnableVertexAttribArray(15); glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(mesh_storage->multimesh_get_color_offset(inst->data->base) * sizeof(float))); glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_custom_offset * sizeof(float)));
glVertexAttribDivisor(15, 1); glVertexAttribDivisor(15, 1);
} }
if (use_index_buffer) { if (use_index_buffer) {
@ -2265,6 +2334,72 @@ void RasterizerSceneGLES3::render_material(const Transform3D &p_cam_transform, c
} }
void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) { void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) {
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
ERR_FAIL_COND(!particles_storage->particles_collision_is_heightfield(p_collider));
Vector3 extents = particles_storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();
Projection cm;
cm.set_orthogonal(-extents.x, extents.x, -extents.z, extents.z, 0, extents.y * 2.0);
Vector3 cam_pos = p_transform.origin;
cam_pos.y += extents.y;
Transform3D cam_xform;
cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_column(Vector3::AXIS_Y), -p_transform.basis.get_column(Vector3::AXIS_Z).normalized());
GLuint fb = particles_storage->particles_collision_get_heightfield_framebuffer(p_collider);
Size2i fb_size = particles_storage->particles_collision_get_heightfield_size(p_collider);
RENDER_TIMESTAMP("Setup GPUParticlesCollisionHeightField3D");
RenderDataGLES3 render_data;
render_data.cam_projection = cm;
render_data.cam_transform = cam_xform;
render_data.view_projection[0] = cm;
render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
render_data.cam_orthogonal = true;
render_data.z_near = 0.0;
render_data.z_far = cm.get_z_far();
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(fb_size), true, Color(), false);
PassMode pass_mode = PASS_MODE_SHADOW;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
RENDER_TIMESTAMP("Render Collider Heightfield");
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb_size.width, fb_size.height);
GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_SCISSOR_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glColorMask(0, 0, 0, 0);
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, 31, false);
_render_list_template<PASS_MODE_SHADOW>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size());
glColorMask(1, 1, 1, 1);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
void RasterizerSceneGLES3::set_time(double p_time, double p_step) { void RasterizerSceneGLES3::set_time(double p_time, double p_step) {
@ -2415,7 +2550,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
global_defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(config->max_renderable_lights) + "\n"; global_defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(config->max_renderable_lights) + "\n";
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
global_defines += "\n#define MAX_FORWARD_LIGHTS " + itos(config->max_lights_per_object) + "\n"; global_defines += "\n#define MAX_FORWARD_LIGHTS uint(" + itos(config->max_lights_per_object) + ")\n";
material_storage->shaders.scene_shader.initialize(global_defines); material_storage->shaders.scene_shader.initialize(global_defines);
scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create(); scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR); material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
@ -2455,7 +2590,6 @@ void fragment() {
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n"; global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n";
material_storage->shaders.sky_shader.initialize(global_defines); material_storage->shaders.sky_shader.initialize(global_defines);
sky_globals.shader_default_version = material_storage->shaders.sky_shader.version_create(); sky_globals.shader_default_version = material_storage->shaders.sky_shader.version_create();
material_storage->shaders.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
} }
{ {
@ -2463,7 +2597,6 @@ void fragment() {
global_defines += "\n#define MAX_SAMPLE_COUNT " + itos(sky_globals.ggx_samples) + "\n"; global_defines += "\n#define MAX_SAMPLE_COUNT " + itos(sky_globals.ggx_samples) + "\n";
material_storage->shaders.cubemap_filter_shader.initialize(global_defines); material_storage->shaders.cubemap_filter_shader.initialize(global_defines);
scene_globals.cubemap_filter_shader_version = material_storage->shaders.cubemap_filter_shader.version_create(); scene_globals.cubemap_filter_shader_version = material_storage->shaders.cubemap_filter_shader.version_create();
material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, CubemapFilterShaderGLES3::MODE_DEFAULT);
} }
{ {

View File

@ -85,16 +85,6 @@ enum SkyUniformLocation {
SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
}; };
enum {
SPEC_CONSTANT_DISABLE_LIGHTMAP = 0,
SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 1,
SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2,
SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3,
SPEC_CONSTANT_DISABLE_FOG = 4,
SPEC_CONSTANT_USE_RADIANCE_MAP = 5,
SPEC_CONSTANT_USE_MULTIVIEW = 6,
};
struct RenderDataGLES3 { struct RenderDataGLES3 {
Ref<RenderSceneBuffersGLES3> render_buffers; Ref<RenderSceneBuffersGLES3> render_buffers;
bool transparent_bg = false; bool transparent_bg = false;

View File

@ -92,7 +92,7 @@ void ShaderGLES3::_add_stage(const char *p_code, StageType p_stage_type) {
} }
} }
void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants) { void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_feedback_count, const Feedback *p_feedback, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants) {
name = p_name; name = p_name;
if (p_vertex_code) { if (p_vertex_code) {
@ -118,6 +118,8 @@ void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code,
} }
variant_defines = p_variants; variant_defines = p_variants;
variant_count = p_variant_count; variant_count = p_variant_count;
feedbacks = p_feedback;
feedback_count = p_feedback_count;
StringBuilder tohash; StringBuilder tohash;
/* /*
@ -339,9 +341,21 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
glAttachShader(spec.id, spec.frag_id); glAttachShader(spec.id, spec.frag_id);
glAttachShader(spec.id, spec.vert_id); glAttachShader(spec.id, spec.vert_id);
//for (int i = 0; i < attribute_pair_count; i++) { // If feedback exists, set it up.
// glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
//} if (feedback_count) {
Vector<const char *> feedback;
for (int i = 0; i < feedback_count; i++) {
if (feedbacks[i].specialization == 0 || (feedbacks[i].specialization & p_specialization)) {
// Specialization for this feedback is enabled
feedback.push_back(feedbacks[i].name);
}
}
if (feedback.size()) {
glTransformFeedbackVaryings(spec.id, feedback.size(), feedback.ptr(), GL_INTERLEAVED_ATTRIBS);
}
}
glLinkProgram(spec.id); glLinkProgram(spec.id);

View File

@ -70,6 +70,11 @@ protected:
bool default_value = false; bool default_value = false;
}; };
struct Feedback {
const char *name;
uint64_t specialization;
};
private: private:
//versions //versions
CharString general_defines; CharString general_defines;
@ -165,6 +170,8 @@ private:
int uniform_count = 0; int uniform_count = 0;
const UBOPair *ubo_pairs = nullptr; const UBOPair *ubo_pairs = nullptr;
int ubo_count = 0; int ubo_count = 0;
const Feedback *feedbacks;
int feedback_count = 0;
const TexUnitPair *texunit_pairs = nullptr; const TexUnitPair *texunit_pairs = nullptr;
int texunit_pair_count = 0; int texunit_pair_count = 0;
int specialization_count = 0; int specialization_count = 0;
@ -178,13 +185,13 @@ private:
protected: protected:
ShaderGLES3(); ShaderGLES3();
void _setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants); void _setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_feedback_count, const Feedback *p_feedback, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants);
_FORCE_INLINE_ void _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) { _FORCE_INLINE_ bool _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) {
ERR_FAIL_INDEX(p_variant, variant_count); ERR_FAIL_INDEX_V(p_variant, variant_count, false);
Version *version = version_owner.get_or_null(p_version); Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND(!version); ERR_FAIL_COND_V(!version, false);
if (version->variants.size() == 0) { if (version->variants.size() == 0) {
_initialize_version(version); //may lack initialization _initialize_version(version); //may lack initialization
@ -210,11 +217,12 @@ protected:
if (!spec || !spec->ok) { if (!spec || !spec->ok) {
WARN_PRINT_ONCE("shader failed to compile, unable to bind shader."); WARN_PRINT_ONCE("shader failed to compile, unable to bind shader.");
return; return false;
} }
glUseProgram(spec->id); glUseProgram(spec->id);
current_shader = spec; current_shader = spec;
return true;
} }
_FORCE_INLINE_ int _version_get_uniform(int p_which, RID p_version, int p_variant, uint64_t p_specialization) { _FORCE_INLINE_ int _version_get_uniform(int p_which, RID p_version, int p_variant, uint64_t p_specialization) {

View File

@ -19,3 +19,5 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("cubemap_filter.glsl") env.GLES3_GLSL("cubemap_filter.glsl")
env.GLES3_GLSL("canvas_occlusion.glsl") env.GLES3_GLSL("canvas_occlusion.glsl")
env.GLES3_GLSL("canvas_sdf.glsl") env.GLES3_GLSL("canvas_sdf.glsl")
env.GLES3_GLSL("particles.glsl")
env.GLES3_GLSL("particles_copy.glsl")

View File

@ -31,7 +31,7 @@ uniform samplerCube source_cube; //texunit:0
uniform int face_id; uniform int face_id;
#ifndef MODE_DIRECT_WRITE #ifndef MODE_DIRECT_WRITE
uniform int sample_count; uniform uint sample_count;
uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT]; uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT];
uniform float weight; uniform float weight;
#endif #endif
@ -105,7 +105,7 @@ void main() {
T[1] = cross(N, T[0]); T[1] = cross(N, T[0]);
T[2] = N; T[2] = N;
for (int sample_num = 0; sample_num < sample_count; sample_num++) { for (uint sample_num = 0u; sample_num < sample_count; sample_num++) {
vec4 sample_direction_mip = sample_directions_mip[sample_num]; vec4 sample_direction_mip = sample_directions_mip[sample_num];
vec3 L = T * sample_direction_mip.xyz; vec3 L = T * sample_direction_mip.xyz;
vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb; vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb;

View File

@ -0,0 +1,501 @@
/* clang-format off */
#[modes]
mode_default =
#[specializations]
MODE_3D = false
USERDATA1_USED = false
USERDATA2_USED = false
USERDATA3_USED = false
USERDATA4_USED = false
USERDATA5_USED = false
USERDATA6_USED = false
#[vertex]
#define SDF_MAX_LENGTH 16384.0
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{ //ubo:2
#MATERIAL_UNIFORMS
};
#endif
/* clang-format on */
#define MAX_ATTRACTORS 32
#define ATTRACTOR_TYPE_SPHERE uint(0)
#define ATTRACTOR_TYPE_BOX uint(1)
#define ATTRACTOR_TYPE_VECTOR_FIELD uint(2)
struct Attractor {
mat4 transform;
vec4 extents; // Extents or radius. w-channel is padding.
uint type;
float strength;
float attenuation;
float directionality;
};
#define MAX_COLLIDERS 32
#define COLLIDER_TYPE_SPHERE uint(0)
#define COLLIDER_TYPE_BOX uint(1)
#define COLLIDER_TYPE_SDF uint(2)
#define COLLIDER_TYPE_HEIGHT_FIELD uint(3)
#define COLLIDER_TYPE_2D_SDF uint(4)
struct Collider {
mat4 transform;
vec4 extents; // Extents or radius. w-channel is padding.
uint type;
float scale;
float pad0;
float pad1;
};
layout(std140) uniform FrameData { //ubo:0
bool emitting;
uint cycle;
float system_phase;
float prev_system_phase;
float explosiveness;
float randomness;
float time;
float delta;
float particle_size;
float pad0;
float pad1;
float pad2;
uint random_seed;
uint attractor_count;
uint collider_count;
uint frame;
mat4 emission_transform;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
};
#define PARTICLE_FLAG_ACTIVE uint(1)
#define PARTICLE_FLAG_STARTED uint(2)
#define PARTICLE_FLAG_TRAILED uint(4)
#define PARTICLE_FRAME_MASK uint(0xFFFF)
#define PARTICLE_FRAME_SHIFT uint(16)
// ParticleData
layout(location = 0) in highp vec4 color;
layout(location = 1) in highp vec4 velocity_flags;
layout(location = 2) in highp vec4 custom;
layout(location = 3) in highp vec4 xform_1;
layout(location = 4) in highp vec4 xform_2;
#ifdef MODE_3D
layout(location = 5) in highp vec4 xform_3;
#endif
#ifdef USERDATA1_USED
layout(location = 6) in highp vec4 userdata1;
#endif
#ifdef USERDATA2_USED
layout(location = 7) in highp vec4 userdata2;
#endif
#ifdef USERDATA3_USED
layout(location = 8) in highp vec4 userdata3;
#endif
#ifdef USERDATA4_USED
layout(location = 9) in highp vec4 userdata4;
#endif
#ifdef USERDATA5_USED
layout(location = 10) in highp vec4 userdata5;
#endif
#ifdef USERDATA6_USED
layout(location = 11) in highp vec4 userdata6;
#endif
out highp vec4 out_color; //tfb:
out highp vec4 out_velocity_flags; //tfb:
out highp vec4 out_custom; //tfb:
out highp vec4 out_xform_1; //tfb:
out highp vec4 out_xform_2; //tfb:
#ifdef MODE_3D
out highp vec4 out_xform_3; //tfb:MODE_3D
#endif
#ifdef USERDATA1_USED
out highp vec4 out_userdata1; //tfb:USERDATA1_USED
#endif
#ifdef USERDATA2_USED
out highp vec4 out_userdata2; //tfb:USERDATA2_USED
#endif
#ifdef USERDATA3_USED
out highp vec4 out_userdata3; //tfb:USERDATA3_USED
#endif
#ifdef USERDATA4_USED
out highp vec4 out_userdata4; //tfb:USERDATA4_USED
#endif
#ifdef USERDATA5_USED
out highp vec4 out_userdata5; //tfb:USERDATA5_USED
#endif
#ifdef USERDATA6_USED
out highp vec4 out_userdata6; //tfb:USERDATA6_USED
#endif
uniform sampler2D height_field_texture; //texunit:0
uniform float lifetime;
uniform bool clear;
uniform uint total_particles;
uniform bool use_fractional_delta;
uint hash(uint x) {
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
x = (x >> uint(16)) ^ x;
return x;
}
vec3 safe_normalize(vec3 direction) {
const float EPSILON = 0.001;
if (length(direction) < EPSILON) {
return vec3(0.0);
}
return normalize(direction);
}
// Needed whenever 2D sdf texture is read from as it is packed in RGBA8.
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;
}
#GLOBALS
void main() {
bool apply_forces = true;
bool apply_velocity = true;
float local_delta = delta;
float mass = 1.0;
bool restart = false;
bool restart_position = false;
bool restart_rotation_scale = false;
bool restart_velocity = false;
bool restart_color = false;
bool restart_custom = false;
mat4 xform = mat4(1.0);
uint flags = 0u;
if (clear) {
out_color = vec4(1.0);
out_custom = vec4(0.0);
out_velocity_flags = vec4(0.0);
} else {
out_color = color;
out_velocity_flags = velocity_flags;
out_custom = custom;
xform[0] = xform_1;
xform[1] = xform_2;
#ifdef MODE_3D
xform[2] = xform_3;
#endif
xform = transpose(xform);
flags = floatBitsToUint(velocity_flags.w);
}
//clear started flag if set
flags &= ~PARTICLE_FLAG_STARTED;
bool collided = false;
vec3 collision_normal = vec3(0.0);
float collision_depth = 0.0;
vec3 attractor_force = vec3(0.0);
#if !defined(DISABLE_VELOCITY)
if (bool(flags & PARTICLE_FLAG_ACTIVE)) {
xform[3].xyz += out_velocity_flags.xyz * local_delta;
}
#endif
uint index = uint(gl_VertexID);
if (emitting) {
float restart_phase = float(index) / float(total_particles);
if (randomness > 0.0) {
uint seed = cycle;
if (restart_phase >= system_phase) {
seed -= uint(1);
}
seed *= uint(total_particles);
seed += index;
float random = float(hash(seed) % uint(65536)) / 65536.0;
restart_phase += randomness * random * 1.0 / float(total_particles);
}
restart_phase *= (1.0 - explosiveness);
if (system_phase > prev_system_phase) {
// restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
if (restart_phase >= prev_system_phase && restart_phase < system_phase) {
restart = true;
if (use_fractional_delta) {
local_delta = (system_phase - restart_phase) * lifetime;
}
}
} else if (delta > 0.0) {
if (restart_phase >= prev_system_phase) {
restart = true;
if (use_fractional_delta) {
local_delta = (1.0 - restart_phase + system_phase) * lifetime;
}
} else if (restart_phase < system_phase) {
restart = true;
if (use_fractional_delta) {
local_delta = (system_phase - restart_phase) * lifetime;
}
}
}
if (restart) {
flags = emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (cycle << PARTICLE_FRAME_SHIFT)) : 0u;
restart_position = true;
restart_rotation_scale = true;
restart_velocity = true;
restart_color = true;
restart_custom = true;
}
}
bool particle_active = bool(flags & PARTICLE_FLAG_ACTIVE);
uint particle_number = (flags >> PARTICLE_FRAME_SHIFT) * uint(total_particles) + index;
if (restart && particle_active) {
#CODE : START
}
if (particle_active) {
for (uint i = 0u; i < attractor_count; i++) {
vec3 dir;
float amount;
vec3 rel_vec = xform[3].xyz - attractors[i].transform[3].xyz;
vec3 local_pos = rel_vec * mat3(attractors[i].transform);
switch (attractors[i].type) {
case ATTRACTOR_TYPE_SPHERE: {
dir = safe_normalize(rel_vec);
float d = length(local_pos) / attractors[i].extents.x;
if (d > 1.0) {
continue;
}
amount = max(0.0, 1.0 - d);
} break;
case ATTRACTOR_TYPE_BOX: {
dir = safe_normalize(rel_vec);
vec3 abs_pos = abs(local_pos / attractors[i].extents.xyz);
float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
if (d > 1.0) {
continue;
}
amount = max(0.0, 1.0 - d);
} break;
case ATTRACTOR_TYPE_VECTOR_FIELD: {
} break;
}
amount = pow(amount, attractors[i].attenuation);
dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality));
attractor_force -= amount * dir * attractors[i].strength;
}
float particle_size = particle_size;
#ifdef USE_COLLISION_SCALE
particle_size *= dot(vec3(length(xform[0].xyz), length(xform[1].xyz), length(xform[2].xyz)), vec3(0.33333333333));
#endif
if (collider_count == 1u && colliders[0].type == COLLIDER_TYPE_2D_SDF) {
//2D collision
vec2 pos = xform[3].xy;
vec4 to_sdf_x = colliders[0].transform[0];
vec4 to_sdf_y = colliders[0].transform[1];
vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
vec4 sdf_to_screen = vec4(colliders[0].extents.xyz, colliders[0].scale);
vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
vec2 pos2 = pos + vec2(0, particle_size);
vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
float sdf_particle_size = distance(sdf_pos, sdf_pos2);
float d = vec4_to_float(texture(height_field_texture, uv_pos)) * SDF_MAX_LENGTH;
d -= sdf_particle_size;
if (d < 0.0) {
const float EPSILON = 0.001;
vec2 n = normalize(vec2(
vec4_to_float(texture(height_field_texture, uv_pos + vec2(EPSILON, 0.0))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(EPSILON, 0.0))),
vec4_to_float(texture(height_field_texture, uv_pos + vec2(0.0, EPSILON))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(0.0, EPSILON)))));
collided = true;
sdf_pos2 = sdf_pos + n * d;
pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[3]));
n = pos - pos2;
collision_normal = normalize(vec3(n, 0.0));
collision_depth = length(n);
}
}
} else {
for (uint i = 0u; i < collider_count; i++) {
vec3 normal;
float depth;
bool col = false;
vec3 rel_vec = xform[3].xyz - colliders[i].transform[3].xyz;
vec3 local_pos = rel_vec * mat3(colliders[i].transform);
switch (colliders[i].type) {
case COLLIDER_TYPE_SPHERE: {
float d = length(rel_vec) - (particle_size + colliders[i].extents.x);
if (d < 0.0) {
col = true;
depth = -d;
normal = normalize(rel_vec);
}
} break;
case COLLIDER_TYPE_BOX: {
vec3 abs_pos = abs(local_pos);
vec3 sgn_pos = sign(local_pos);
if (any(greaterThan(abs_pos, colliders[i].extents.xyz))) {
//point outside box
vec3 closest = min(abs_pos, colliders[i].extents.xyz);
vec3 rel = abs_pos - closest;
depth = length(rel) - particle_size;
if (depth < 0.0) {
col = true;
normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
depth = -depth;
}
} else {
//point inside box
vec3 axis_len = colliders[i].extents.xyz - abs_pos;
// there has to be a faster way to do this?
if (all(lessThan(axis_len.xx, axis_len.yz))) {
normal = vec3(1, 0, 0);
} else if (all(lessThan(axis_len.yy, axis_len.xz))) {
normal = vec3(0, 1, 0);
} else {
normal = vec3(0, 0, 1);
}
col = true;
depth = dot(normal * axis_len, vec3(1)) + particle_size;
normal = mat3(colliders[i].transform) * (normal * sgn_pos);
}
} break;
case COLLIDER_TYPE_SDF: {
} break;
case COLLIDER_TYPE_HEIGHT_FIELD: {
vec3 local_pos_bottom = local_pos;
local_pos_bottom.y -= particle_size;
if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
continue;
}
const float DELTA = 1.0 / 8192.0;
vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
if (y > uvw_pos.y) {
//inside heightfield
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
col = true;
depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
}
} break;
}
if (col) {
if (!collided) {
collided = true;
collision_normal = normal;
collision_depth = depth;
} else {
vec3 c = collision_normal * collision_depth;
c += normal * max(0.0, depth - dot(normal, c));
collision_normal = normalize(c);
collision_depth = length(c);
}
}
}
}
}
if (particle_active) {
#CODE : PROCESS
}
flags &= ~PARTICLE_FLAG_ACTIVE;
if (particle_active) {
flags |= PARTICLE_FLAG_ACTIVE;
}
xform = transpose(xform);
out_xform_1 = xform[0];
out_xform_2 = xform[1];
#ifdef MODE_3D
out_xform_3 = xform[2];
#endif
out_velocity_flags.w = uintBitsToFloat(flags);
}
/* clang-format off */
#[fragment]
void main() {
}
/* clang-format on */

View File

@ -0,0 +1,122 @@
/* clang-format off */
#[modes]
mode_default =
#[specializations]
MODE_3D = false
#[vertex]
#include "stdlib_inc.glsl"
// ParticleData
layout(location = 0) in highp vec4 color;
layout(location = 1) in highp vec4 velocity_flags;
layout(location = 2) in highp vec4 custom;
layout(location = 3) in highp vec4 xform_1;
layout(location = 4) in highp vec4 xform_2;
#ifdef MODE_3D
layout(location = 5) in highp vec4 xform_3;
#endif
/* clang-format on */
out highp vec4 out_xform_1; //tfb:
out highp vec4 out_xform_2; //tfb:
#ifdef MODE_3D
out highp vec4 out_xform_3; //tfb:MODE_3D
#endif
flat out highp uvec4 instance_color_custom_data; //tfb:
uniform lowp vec3 sort_direction;
uniform highp float frame_remainder;
uniform highp vec3 align_up;
uniform highp uint align_mode;
uniform highp mat4 inv_emission_transform;
#define TRANSFORM_ALIGN_DISABLED uint(0)
#define TRANSFORM_ALIGN_Z_BILLBOARD uint(1)
#define TRANSFORM_ALIGN_Y_TO_VELOCITY uint(2)
#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY uint(3)
#define PARTICLE_FLAG_ACTIVE uint(1)
void main() {
mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); // zero scale, becomes invisible.
if (bool(floatBitsToUint(velocity_flags.w) & PARTICLE_FLAG_ACTIVE)) {
#ifdef MODE_3D
txform = transpose(mat4(xform_1, xform_2, xform_3, vec4(0.0, 0.0, 0.0, 1.0)));
#else
txform = transpose(mat4(xform_1, xform_2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
#endif
switch (align_mode) {
case TRANSFORM_ALIGN_DISABLED: {
} break; //nothing
case TRANSFORM_ALIGN_Z_BILLBOARD: {
mat3 local = mat3(normalize(cross(align_up, sort_direction)), align_up, sort_direction);
local = local * mat3(txform);
txform[0].xyz = local[0];
txform[1].xyz = local[1];
txform[2].xyz = local[2];
} break;
case TRANSFORM_ALIGN_Y_TO_VELOCITY: {
vec3 v = velocity_flags.xyz;
float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
if (length(v) > 0.0) {
txform[1].xyz = normalize(v);
} else {
txform[1].xyz = normalize(txform[1].xyz);
}
txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz));
txform[2].xyz = vec3(0.0, 0.0, 1.0) * s;
txform[0].xyz *= s;
txform[1].xyz *= s;
} break;
case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: {
vec3 sv = velocity_flags.xyz - sort_direction * dot(sort_direction, velocity_flags.xyz); //screen velocity
float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
if (length(sv) == 0.0) {
sv = align_up;
}
sv = normalize(sv);
txform[0].xyz = normalize(cross(sv, sort_direction)) * s;
txform[1].xyz = sv * s;
txform[2].xyz = sort_direction * s;
} break;
}
txform[3].xyz += velocity_flags.xyz * frame_remainder;
#ifndef MODE_3D
// In global mode, bring 2D particles to local coordinates
// as they will be drawn with the node position as origin.
txform = inv_emission_transform * txform;
#endif
txform = transpose(txform);
}
instance_color_custom_data = uvec4(packHalf2x16(color.xy), packHalf2x16(color.zw), packHalf2x16(custom.xy), packHalf2x16(custom.zw));
out_xform_1 = txform[0];
out_xform_2 = txform[1];
#ifdef MODE_3D
out_xform_3 = txform[2];
#endif
}
/* clang-format off */
#[fragment]
void main() {
}
/* clang-format on */

View File

@ -197,7 +197,7 @@ out vec3 tangent_interp;
out vec3 binormal_interp; out vec3 binormal_interp;
#endif #endif
#if defined(MATERIAL_UNIFORMS_USED) #ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */ /* clang-format off */
layout(std140) uniform MaterialUniforms { // ubo:3 layout(std140) uniform MaterialUniforms { // ubo:3
@ -366,7 +366,9 @@ void main() {
#endif #endif
#endif #endif
#ifndef MODE_RENDER_DEPTH
#include "tonemap_inc.glsl" #include "tonemap_inc.glsl"
#endif
#include "stdlib_inc.glsl" #include "stdlib_inc.glsl"
/* texture unit usage, N is max_texture_unity-N /* texture unit usage, N is max_texture_unity-N
@ -428,7 +430,7 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1
/* Material Uniforms */ /* Material Uniforms */
#if defined(MATERIAL_UNIFORMS_USED) #ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */ /* clang-format off */
layout(std140) uniform MaterialUniforms { // ubo:3 layout(std140) uniform MaterialUniforms { // ubo:3
@ -535,7 +537,7 @@ layout(std140) uniform OmniLightData { // ubo:5
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
}; };
uniform uint omni_light_indices[MAX_FORWARD_LIGHTS]; uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
uniform int omni_light_count; uniform uint omni_light_count;
#endif #endif
#ifndef DISABLE_LIGHT_SPOT #ifndef DISABLE_LIGHT_SPOT
@ -545,7 +547,7 @@ layout(std140) uniform SpotLightData { // ubo:6
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
}; };
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS]; uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
uniform int spot_light_count; uniform uint spot_light_count;
#endif #endif
#ifdef USE_ADDITIVE_LIGHTING #ifdef USE_ADDITIVE_LIGHTING
@ -1188,7 +1190,7 @@ void main() {
#endif //!DISABLE_LIGHT_DIRECTIONAL #endif //!DISABLE_LIGHT_DIRECTIONAL
#ifndef DISABLE_LIGHT_OMNI #ifndef DISABLE_LIGHT_OMNI
for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) { for (uint i = 0u; i < MAX_FORWARD_LIGHTS; i++) {
if (i >= omni_light_count) { if (i >= omni_light_count) {
break; break;
} }
@ -1211,7 +1213,7 @@ void main() {
#endif // !DISABLE_LIGHT_OMNI #endif // !DISABLE_LIGHT_OMNI
#ifndef DISABLE_LIGHT_SPOT #ifndef DISABLE_LIGHT_SPOT
for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) { for (uint i = 0u; i < MAX_FORWARD_LIGHTS; i++) {
if (i >= spot_light_count) { if (i >= spot_light_count) {
break; break;
} }

View File

@ -34,6 +34,7 @@
#include "config.h" #include "config.h"
#include "material_storage.h" #include "material_storage.h"
#include "particles_storage.h"
#include "texture_storage.h" #include "texture_storage.h"
#include "drivers/gles3/rasterizer_canvas_gles3.h" #include "drivers/gles3/rasterizer_canvas_gles3.h"
@ -1342,13 +1343,13 @@ MaterialStorage::MaterialStorage() {
shader_data_request_func[RS::SHADER_SPATIAL] = _create_scene_shader_func; shader_data_request_func[RS::SHADER_SPATIAL] = _create_scene_shader_func;
shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func; shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func;
shader_data_request_func[RS::SHADER_PARTICLES] = nullptr; shader_data_request_func[RS::SHADER_PARTICLES] = _create_particles_shader_func;
shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func; shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func;
shader_data_request_func[RS::SHADER_FOG] = nullptr; shader_data_request_func[RS::SHADER_FOG] = nullptr;
material_data_request_func[RS::SHADER_SPATIAL] = _create_scene_material_func; material_data_request_func[RS::SHADER_SPATIAL] = _create_scene_material_func;
material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func; material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func;
material_data_request_func[RS::SHADER_PARTICLES] = nullptr; material_data_request_func[RS::SHADER_PARTICLES] = _create_particles_material_func;
material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func; material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
material_data_request_func[RS::SHADER_FOG] = nullptr; material_data_request_func[RS::SHADER_FOG] = nullptr;
@ -1613,32 +1614,32 @@ MaterialStorage::MaterialStorage() {
{ {
// Setup Particles compiler // Setup Particles compiler
/*
ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["COLOR"] = "PARTICLE.color"; ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["VELOCITY"] = "PARTICLE.velocity";
actions.renames["COLOR"] = "out_color";
actions.renames["VELOCITY"] = "out_velocity_flags.xyz";
//actions.renames["MASS"] = "mass"; ? //actions.renames["MASS"] = "mass"; ?
actions.renames["ACTIVE"] = "particle_active"; actions.renames["ACTIVE"] = "particle_active";
actions.renames["RESTART"] = "restart"; actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom"; actions.renames["CUSTOM"] = "out_custom";
for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) { for (int i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
String udname = "USERDATA" + itos(i + 1); String udname = "USERDATA" + itos(i + 1);
actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1); actions.renames[udname] = "out_userdata" + itos(i + 1);
actions.usage_defines[udname] = "#define USERDATA" + itos(i + 1) + "_USED\n"; actions.usage_defines[udname] = "#define USERDATA" + itos(i + 1) + "_USED\n";
} }
actions.renames["TRANSFORM"] = "PARTICLE.xform"; actions.renames["TRANSFORM"] = "xform";
actions.renames["TIME"] = "frame_history.data[0].time"; actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI); actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU); actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E); actions.renames["E"] = _MKSTR(Math_E);
actions.renames["LIFETIME"] = "params.lifetime"; actions.renames["LIFETIME"] = "lifetime";
actions.renames["DELTA"] = "local_delta"; actions.renames["DELTA"] = "local_delta";
actions.renames["NUMBER"] = "particle_number"; actions.renames["NUMBER"] = "particle_number";
actions.renames["INDEX"] = "index"; actions.renames["INDEX"] = "index";
//actions.renames["GRAVITY"] = "current_gravity"; //actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform"; actions.renames["EMISSION_TRANSFORM"] = "emission_transform";
actions.renames["RANDOM_SEED"] = "FRAME.random_seed"; actions.renames["RANDOM_SEED"] = "random_seed";
actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION"; actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE"; actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
actions.renames["FLAG_EMIT_VELOCITY"] = "EMISSION_FLAG_HAS_VELOCITY"; actions.renames["FLAG_EMIT_VELOCITY"] = "EMISSION_FLAG_HAS_VELOCITY";
@ -1660,18 +1661,10 @@ ShaderCompiler::DefaultIdentifierActions actions;
actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISION_SCALE\n"; actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISION_SCALE\n";
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = 3;
actions.base_uniform_string = "material.";
actions.base_varying_index = 10;
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_shader_uniforms.data";
particles_shader.compiler.initialize(actions); shaders.compiler_particles.initialize(actions);
*/
} }
{ {
@ -2470,8 +2463,8 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
RS::ShaderMode new_mode; RS::ShaderMode new_mode;
if (mode_string == "canvas_item") { if (mode_string == "canvas_item") {
new_mode = RS::SHADER_CANVAS_ITEM; new_mode = RS::SHADER_CANVAS_ITEM;
//} else if (mode_string == "particles") { } else if (mode_string == "particles") {
// new_mode = RS::SHADER_PARTICLES; new_mode = RS::SHADER_PARTICLES;
} else if (mode_string == "spatial") { } else if (mode_string == "spatial") {
new_mode = RS::SHADER_SPATIAL; new_mode = RS::SHADER_SPATIAL;
} else if (mode_string == "sky") { } else if (mode_string == "sky") {
@ -2542,6 +2535,9 @@ void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
ERR_FAIL_COND(!shader); ERR_FAIL_COND(!shader);
shader->path_hint = p_path; shader->path_hint = p_path;
if (shader->data) {
shader->data->set_path_hint(p_path);
}
} }
String MaterialStorage::shader_get_code(RID p_shader) const { String MaterialStorage::shader_get_code(RID p_shader) const {
@ -2809,6 +2805,10 @@ void MaterialStorage::material_update_dependency(RID p_material, DependencyTrack
/* Canvas Shader Data */ /* Canvas Shader Data */
void CanvasShaderData::set_path_hint(const String &p_path) {
path = p_path;
}
void CanvasShaderData::set_code(const String &p_code) { void CanvasShaderData::set_code(const String &p_code) {
// compile the shader // compile the shader
@ -3007,7 +3007,7 @@ GLES3::ShaderData *GLES3::_create_canvas_shader_func() {
} }
void CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { void CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size); update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
} }
void CanvasMaterialData::bind_uniforms() { void CanvasMaterialData::bind_uniforms() {
@ -3043,6 +3043,10 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// SKY SHADER // SKY SHADER
void SkyShaderData::set_path_hint(const String &p_path) {
path = p_path;
}
void SkyShaderData::set_code(const String &p_code) { void SkyShaderData::set_code(const String &p_code) {
//compile //compile
@ -3251,7 +3255,7 @@ GLES3::ShaderData *GLES3::_create_sky_shader_func() {
void SkyMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { void SkyMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
uniform_set_updated = true; uniform_set_updated = true;
return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size); update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
} }
SkyMaterialData::~SkyMaterialData() { SkyMaterialData::~SkyMaterialData() {
@ -3286,6 +3290,10 @@ void SkyMaterialData::bind_uniforms() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Scene SHADER // Scene SHADER
void SceneShaderData::set_path_hint(const String &p_path) {
path = p_path;
}
void SceneShaderData::set_code(const String &p_code) { void SceneShaderData::set_code(const String &p_code) {
//compile //compile
@ -3586,7 +3594,7 @@ void SceneMaterialData::set_next_pass(RID p_pass) {
} }
void SceneMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { void SceneMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size); update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
} }
SceneMaterialData::~SceneMaterialData() { SceneMaterialData::~SceneMaterialData() {
@ -3619,4 +3627,209 @@ void SceneMaterialData::bind_uniforms() {
} }
} }
/* Particles SHADER */
void ParticlesShaderData::set_path_hint(const String &p_path) {
path = p_path;
}
void ParticlesShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
uses_collision = false;
if (code.is_empty()) {
return; //just invalid, but no error
}
ShaderCompiler::GeneratedCode gen_code;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["start"] = ShaderCompiler::STAGE_VERTEX;
actions.entry_point_stages["process"] = ShaderCompiler::STAGE_VERTEX;
actions.usage_flag_pointers["COLLIDED"] = &uses_collision;
userdata_count = 0;
for (uint32_t i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
userdatas_used[i] = false;
actions.usage_flag_pointers["USERDATA" + itos(i + 1)] = &userdatas_used[i];
}
actions.uniforms = &uniforms;
Error err = MaterialStorage::get_singleton()->shaders.compiler_particles.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = MaterialStorage::get_singleton()->shaders.particles_process_shader.version_create();
}
for (uint32_t i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
if (userdatas_used[i]) {
userdata_count++;
}
}
Vector<StringName> texture_uniform_names;
for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
}
MaterialStorage::get_singleton()->shaders.particles_process_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.particles_process_shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
valid = true;
}
void ParticlesShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
if (default_texture_params[p_name].is_empty()) {
default_texture_params.erase(p_name);
}
}
} else {
if (!default_texture_params.has(p_name)) {
default_texture_params[p_name] = HashMap<int, RID>();
}
default_texture_params[p_name][p_index] = p_texture;
}
}
void ParticlesShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
if (E.value.texture_order >= 0) {
order[E.value.texture_order + 100000] = E.key;
} else {
order[E.value.order] = E.key;
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);
}
}
void ParticlesShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererMaterialStorage::InstanceShaderParam p;
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
bool ParticlesShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
return uniforms[p_param].texture_order >= 0;
}
bool ParticlesShaderData::is_animated() const {
return false;
}
bool ParticlesShaderData::casts_shadows() const {
return false;
}
Variant ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const {
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
RS::ShaderNativeSourceCode ParticlesShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.particles_process_shader.version_get_native_source_code(version);
}
ParticlesShaderData::~ParticlesShaderData() {
if (version.is_valid()) {
MaterialStorage::get_singleton()->shaders.particles_process_shader.version_free(version);
}
}
GLES3::ShaderData *GLES3::_create_particles_shader_func() {
ParticlesShaderData *shader_data = memnew(ParticlesShaderData);
return shader_data;
}
void ParticleProcessMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
}
ParticleProcessMaterialData::~ParticleProcessMaterialData() {
}
GLES3::MaterialData *GLES3::_create_particles_material_func(ShaderData *p_shader) {
ParticleProcessMaterialData *material_data = memnew(ParticleProcessMaterialData);
material_data->shader_data = static_cast<ParticlesShaderData *>(p_shader);
//update will happen later anyway so do nothing.
return material_data;
}
void ParticleProcessMaterialData::bind_uniforms() {
// Bind Material Uniforms
glBindBufferBase(GL_UNIFORM_BUFFER, GLES3::PARTICLES_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
RID *textures = texture_cache.ptrw();
ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
for (int ti = 0; ti < texture_cache.size(); ti++) {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 becuase texture slot 0 is reserved for the heightmap texture.
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
// Set sampler state here as the same texture can be used in multiple places with different flags
// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
texture->gl_set_filter(filter);
texture->gl_set_repeat(repeat);
}
}
#endif // !GLES3_ENABLED #endif // !GLES3_ENABLED

View File

@ -44,6 +44,7 @@
#include "../shaders/canvas.glsl.gen.h" #include "../shaders/canvas.glsl.gen.h"
#include "../shaders/cubemap_filter.glsl.gen.h" #include "../shaders/cubemap_filter.glsl.gen.h"
#include "../shaders/particles.glsl.gen.h"
#include "../shaders/scene.glsl.gen.h" #include "../shaders/scene.glsl.gen.h"
#include "../shaders/sky.glsl.gen.h" #include "../shaders/sky.glsl.gen.h"
@ -53,6 +54,7 @@ namespace GLES3 {
struct ShaderData { struct ShaderData {
virtual void set_code(const String &p_Code) = 0; virtual void set_code(const String &p_Code) = 0;
virtual void set_path_hint(const String &p_hint) = 0;
virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 0; virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 0;
virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0; virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
@ -165,6 +167,7 @@ struct CanvasShaderData : public ShaderData {
bool uses_time = false; bool uses_time = false;
virtual void set_code(const String &p_Code); virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_hint);
virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index); virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const; virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const; virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
@ -216,6 +219,7 @@ struct SkyShaderData : public ShaderData {
bool uses_light; bool uses_light;
virtual void set_code(const String &p_Code); virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_hint);
virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index); virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const; virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const; virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
@ -337,6 +341,7 @@ struct SceneShaderData : public ShaderData {
uint32_t index = 0; uint32_t index = 0;
virtual void set_code(const String &p_Code); virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_hint);
virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index); virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const; virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const; virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
@ -368,6 +373,62 @@ struct SceneMaterialData : public MaterialData {
MaterialData *_create_scene_material_func(ShaderData *p_shader); MaterialData *_create_scene_material_func(ShaderData *p_shader);
/* Particle Shader */
enum {
PARTICLES_MAX_USERDATAS = 6
};
struct ParticlesShaderData : public ShaderData {
bool valid = false;
RID version;
bool uses_collision = false;
HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String path;
String code;
HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_time = false;
bool userdatas_used[PARTICLES_MAX_USERDATAS] = {};
uint32_t userdata_count = 0;
virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_hint);
virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
ParticlesShaderData() {}
virtual ~ParticlesShaderData();
};
ShaderData *_create_particles_shader_func();
struct ParticleProcessMaterialData : public MaterialData {
ParticlesShaderData *shader_data = nullptr;
RID uniform_set;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual void bind_uniforms();
virtual ~ParticleProcessMaterialData();
};
MaterialData *_create_particles_material_func(ShaderData *p_shader);
/* Global shader uniform structs */ /* Global shader uniform structs */
struct GlobalShaderUniforms { struct GlobalShaderUniforms {
enum { enum {
@ -504,6 +565,7 @@ public:
SkyShaderGLES3 sky_shader; SkyShaderGLES3 sky_shader;
SceneShaderGLES3 scene_shader; SceneShaderGLES3 scene_shader;
CubemapFilterShaderGLES3 cubemap_filter_shader; CubemapFilterShaderGLES3 cubemap_filter_shader;
ParticlesShaderGLES3 particles_process_shader;
ShaderCompiler compiler_canvas; ShaderCompiler compiler_canvas;
ShaderCompiler compiler_scene; ShaderCompiler compiler_scene;

View File

@ -87,8 +87,11 @@ void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count
ERR_FAIL_COND(!mesh); ERR_FAIL_COND(!mesh);
ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
WARN_PRINT_ONCE("blend shapes not supported by GLES3 renderer yet");
mesh->blend_shape_count = p_blend_shape_count; mesh->blend_shape_count = p_blend_shape_count;
if (p_blend_shape_count > 0) {
WARN_PRINT_ONCE("blend shapes not supported by GLES3 renderer yet");
}
} }
bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {

View File

@ -327,6 +327,7 @@ public:
_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const { _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
ERR_FAIL_COND_V(!s, 0);
int32_t current_lod = -1; int32_t current_lod = -1;
r_index_count = s->index_count; r_index_count = s->index_count;
@ -403,6 +404,8 @@ public:
virtual void mesh_instance_check_for_update(RID p_mesh_instance) override; virtual void mesh_instance_check_for_update(RID p_mesh_instance) override;
virtual void update_mesh_instances() override; virtual void update_mesh_instances() override;
// TODO: considering hashing versions with multimesh buffer RID.
// Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, GLuint &r_vertex_array_gl) { _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
ERR_FAIL_COND(!mi); ERR_FAIL_COND(!mi);

File diff suppressed because it is too large Load Diff

View File

@ -33,25 +33,283 @@
#ifdef GLES3_ENABLED #ifdef GLES3_ENABLED
#include "../shaders/particles_copy.glsl.gen.h"
#include "core/templates/local_vector.h" #include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h" #include "core/templates/rid_owner.h"
#include "core/templates/self_list.h" #include "core/templates/self_list.h"
#include "servers/rendering/storage/particles_storage.h" #include "servers/rendering/storage/particles_storage.h"
#include "servers/rendering/storage/utilities.h"
#include "platform_config.h"
#ifndef OPENGL_INCLUDE_H
#include <GLES3/gl3.h>
#else
#include OPENGL_INCLUDE_H
#endif
namespace GLES3 { namespace GLES3 {
enum ParticlesUniformLocation {
PARTICLES_FRAME_UNIFORM_LOCATION,
PARTICLES_GLOBALS_UNIFORM_LOCATION,
PARTICLES_MATERIAL_UNIFORM_LOCATION,
};
class ParticlesStorage : public RendererParticlesStorage { class ParticlesStorage : public RendererParticlesStorage {
private: private:
static ParticlesStorage *singleton; static ParticlesStorage *singleton;
/* PARTICLES */
struct ParticleInstanceData3D {
float xform[12];
float color[2]; // Color and custom are packed together into one vec4;
float custom[2];
};
struct ParticleInstanceData2D {
float xform[8];
float color[2]; // Color and custom are packed together into one vec4;
float custom[2];
};
struct ParticlesViewSort {
Vector3 z_dir;
bool operator()(const ParticleInstanceData3D &p_a, const ParticleInstanceData3D &p_b) const {
return z_dir.dot(Vector3(p_a.xform[3], p_a.xform[7], p_a.xform[11])) < z_dir.dot(Vector3(p_b.xform[3], p_b.xform[7], p_b.xform[11]));
}
};
struct ParticlesFrameParams {
enum {
MAX_ATTRACTORS = 32,
MAX_COLLIDERS = 32,
MAX_3D_TEXTURES = 0 // GLES3 renderer doesn't support using 3D textures for flow field or collisions.
};
enum AttractorType {
ATTRACTOR_TYPE_SPHERE,
ATTRACTOR_TYPE_BOX,
ATTRACTOR_TYPE_VECTOR_FIELD,
};
struct Attractor {
float transform[16];
float extents[4]; // Extents or radius. w-channel is padding.
uint32_t type;
float strength;
float attenuation;
float directionality;
};
enum CollisionType {
COLLISION_TYPE_SPHERE,
COLLISION_TYPE_BOX,
COLLISION_TYPE_SDF,
COLLISION_TYPE_HEIGHT_FIELD,
COLLISION_TYPE_2D_SDF,
};
struct Collider {
float transform[16];
float extents[4]; // Extents or radius. w-channel is padding.
uint32_t type;
float scale;
float pad0;
float pad1;
};
uint32_t emitting;
uint32_t cycle;
float system_phase;
float prev_system_phase;
float explosiveness;
float randomness;
float time;
float delta;
float particle_size;
float pad0;
float pad1;
float pad2;
uint32_t random_seed;
uint32_t attractor_count;
uint32_t collider_count;
uint32_t frame;
float emission_transform[16];
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
};
struct Particles {
RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
bool inactive = true;
double inactive_time = 0.0;
bool emitting = false;
bool one_shot = false;
int amount = 0;
double lifetime = 1.0;
double pre_process_time = 0.0;
real_t explosiveness = 0.0;
real_t randomness = 0.0;
bool restart_request = false;
AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
bool use_local_coords = false;
bool has_collision_cache = false;
bool has_sdf_collision = false;
Transform2D sdf_collision_transform;
Rect2 sdf_collision_to_screen;
GLuint sdf_collision_texture = 0;
RID process_material;
uint32_t frame_counter = 0;
RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
Vector<RID> draw_passes;
GLuint frame_params_ubo = 0;
// We may process particles multiple times each frame (if they have a fixed FPS higher than the game FPS).
// Unfortunately, this means we can't just use a round-robin system of 3 buffers.
// To ensure the sort buffer is accurate, we copy the last frame instance buffer just before processing.
// Transform Feedback buffer and VAO for rendering.
// Each frame we render to this one.
GLuint front_vertex_array = 0; // Binds process buffer. Used for processing.
GLuint front_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
GLuint front_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
// VAO for transform feedback, contains last frame's data.
// Read from this one for particles process and then copy to last frame buffer.
GLuint back_vertex_array = 0; // Binds process buffer. Used for processing.
GLuint back_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
GLuint back_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
uint32_t instance_buffer_size_cache = 0;
uint32_t instance_buffer_stride_cache = 0;
uint32_t num_attrib_arrays_cache = 0;
uint32_t process_buffer_stride_cache = 0;
// Only ever copied to, holds last frame's instance data, then swaps with sort_buffer.
GLuint last_frame_buffer = 0;
bool last_frame_buffer_filled = false;
float last_frame_phase = 0.0;
// The frame-before-last's instance buffer.
// Use this to copy data back for sorting or computing AABB.
GLuint sort_buffer = 0;
bool sort_buffer_filled = false;
float sort_buffer_phase = 0.0;
uint32_t userdata_count = 0;
bool dirty = false;
Particles *update_list = nullptr;
double phase = 0.0;
double prev_phase = 0.0;
uint64_t prev_ticks = 0;
uint32_t random_seed = 0;
uint32_t cycle_number = 0;
double speed_scale = 1.0;
int fixed_fps = 30;
bool interpolate = true;
bool fractional_delta = false;
double frame_remainder = 0;
real_t collision_base_size = 0.01;
bool clear = true;
Transform3D emission_transform;
HashSet<RID> collisions;
Dependency dependency;
double trail_length = 1.0;
bool trails_enabled = false;
Particles() {
}
};
void _particles_process(Particles *p_particles, double p_delta);
void _particles_free_data(Particles *particles);
void _particles_update_buffers(Particles *particles);
void _particles_allocate_history_buffers(Particles *particles);
void _particles_update_instance_buffer(Particles *particles, const Vector3 &p_axis, const Vector3 &p_up_axis);
template <typename T>
void _particles_reverse_lifetime_sort(Particles *particles);
struct ParticlesShader {
RID default_shader;
RID default_material;
RID default_shader_version;
ParticlesCopyShaderGLES3 copy_shader;
RID copy_shader_version;
} particles_shader;
Particles *particle_update_list = nullptr;
mutable RID_Owner<Particles, true> particles_owner;
/* Particles Collision */
struct ParticlesCollision {
RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT;
uint32_t cull_mask = 0xFFFFFFFF;
float radius = 1.0;
Vector3 extents = Vector3(1, 1, 1);
float attractor_strength = 1.0;
float attractor_attenuation = 1.0;
float attractor_directionality = 0.0;
GLuint field_texture = 0;
GLuint heightfield_texture = 0;
GLuint heightfield_fb = 0;
Size2i heightfield_fb_size;
RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
Dependency dependency;
};
struct ParticlesCollisionInstance {
RID collision;
Transform3D transform;
bool active = false;
};
mutable RID_Owner<ParticlesCollision, true> particles_collision_owner;
mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
public: public:
static ParticlesStorage *get_singleton(); static ParticlesStorage *get_singleton();
ParticlesStorage(); ParticlesStorage();
virtual ~ParticlesStorage(); virtual ~ParticlesStorage();
bool free(RID p_rid);
/* PARTICLES */ /* PARTICLES */
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
virtual RID particles_allocate() override; virtual RID particles_allocate() override;
virtual void particles_initialize(RID p_rid) override; virtual void particles_initialize(RID p_rid) override;
virtual void particles_free(RID p_rid) override; virtual void particles_free(RID p_rid) override;
@ -102,12 +360,51 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_instance) override; virtual void particles_add_collision(RID p_particles, RID p_instance) override;
virtual void particles_remove_collision(RID p_particles, RID p_instance) override; virtual void particles_remove_collision(RID p_particles, RID p_instance) override;
virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override; void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture);
virtual void update_particles() override; virtual void update_particles() override;
virtual bool particles_is_inactive(RID p_particles) const override; virtual bool particles_is_inactive(RID p_particles) const override;
_FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
return particles->mode;
}
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, 0);
return particles->amount;
}
_FORCE_INLINE_ GLuint particles_get_gl_buffer(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
if ((particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME) && particles->sort_buffer_filled) {
return particles->sort_buffer;
}
return particles->back_instance_buffer;
}
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, 0);
return particles->has_collision_cache;
}
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND_V(!particles, false);
return particles->use_local_coords;
}
Dependency *particles_get_dependency(RID p_particles) const;
/* PARTICLES COLLISION */ /* PARTICLES COLLISION */
bool owns_particles_collision(RID p_rid) { return particles_collision_owner.owns(p_rid); }
virtual RID particles_collision_allocate() override; virtual RID particles_collision_allocate() override;
virtual void particles_collision_initialize(RID p_rid) override; virtual void particles_collision_initialize(RID p_rid) override;
@ -124,8 +421,22 @@ public:
virtual void particles_collision_height_field_update(RID p_particles_collision) override; virtual void particles_collision_height_field_update(RID p_particles_collision) override;
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override; virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override;
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override; virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override;
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override; virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override; GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
_FORCE_INLINE_ Size2i particles_collision_get_heightfield_size(RID p_particles_collision) const {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
ERR_FAIL_COND_V(!particles_collision, Size2i());
ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, Size2i());
return particles_collision->heightfield_fb_size;
}
Dependency *particles_collision_get_dependency(RID p_particles) const;
/* PARTICLES COLLISION INSTANCE*/
bool owns_particles_collision_instance(RID p_rid) { return particles_collision_instance_owner.owns(p_rid); }
virtual RID particles_collision_instance_create(RID p_collision) override; virtual RID particles_collision_instance_create(RID p_collision) override;
virtual void particles_collision_instance_free(RID p_rid) override; virtual void particles_collision_instance_free(RID p_rid) override;

View File

@ -647,7 +647,7 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
texture.height = p_image->get_height(); texture.height = p_image->get_height();
texture.alloc_width = texture.width; texture.alloc_width = texture.width;
texture.alloc_height = texture.height; texture.alloc_height = texture.height;
texture.mipmaps = p_image->get_mipmap_count(); texture.mipmaps = p_image->get_mipmap_count() + 1;
texture.format = p_image->get_format(); texture.format = p_image->get_format();
texture.type = Texture::TYPE_2D; texture.type = Texture::TYPE_2D;
texture.target = GL_TEXTURE_2D; texture.target = GL_TEXTURE_2D;
@ -2215,7 +2215,11 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) {
// Load // Load
CanvasSdfShaderGLES3::ShaderVariant variant = shrink ? CanvasSdfShaderGLES3::MODE_LOAD_SHRINK : CanvasSdfShaderGLES3::MODE_LOAD; CanvasSdfShaderGLES3::ShaderVariant variant = shrink ? CanvasSdfShaderGLES3::MODE_LOAD_SHRINK : CanvasSdfShaderGLES3::MODE_LOAD;
sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant); bool success = sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
if (!success) {
return;
}
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, 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::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::STRIDE, 0, sdf_shader.shader_version, variant);
@ -2236,7 +2240,11 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) {
int stride = nearest_power_of_2_templated(MAX(size.width, size.height) / 2); int stride = nearest_power_of_2_templated(MAX(size.width, size.height) / 2);
variant = CanvasSdfShaderGLES3::MODE_PROCESS; variant = CanvasSdfShaderGLES3::MODE_PROCESS;
sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant); success = sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
if (!success) {
return;
}
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, 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::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::STRIDE, stride, sdf_shader.shader_version, variant);
@ -2260,7 +2268,11 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) {
// Store // Store
variant = shrink ? CanvasSdfShaderGLES3::MODE_STORE_SHRINK : CanvasSdfShaderGLES3::MODE_STORE; variant = shrink ? CanvasSdfShaderGLES3::MODE_STORE_SHRINK : CanvasSdfShaderGLES3::MODE_STORE;
sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant); success = sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
if (!success) {
return;
}
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, 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::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::STRIDE, stride, sdf_shader.shader_version, variant);

View File

@ -108,6 +108,10 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const {
return RS::INSTANCE_LIGHT; return RS::INSTANCE_LIGHT;
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) { } else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
return RS::INSTANCE_LIGHTMAP; return RS::INSTANCE_LIGHTMAP;
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
return RS::INSTANCE_PARTICLES;
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
return RS::INSTANCE_PARTICLES_COLLISION;
} }
return RS::INSTANCE_NONE; return RS::INSTANCE_NONE;
} }
@ -143,53 +147,18 @@ bool Utilities::free(RID p_rid) {
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) { } else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
GLES3::LightStorage::get_singleton()->lightmap_free(p_rid); GLES3::LightStorage::get_singleton()->lightmap_free(p_rid);
return true; return true;
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
GLES3::ParticlesStorage::get_singleton()->particles_free(p_rid);
return true;
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
GLES3::ParticlesStorage::get_singleton()->particles_collision_free(p_rid);
return true;
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) {
GLES3::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid);
return true;
} else { } else {
return false; return false;
} }
/*
else if (reflection_probe_owner.owns(p_rid)) {
// delete the texture
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid);
reflection_probe->instance_remove_deps();
reflection_probe_owner.free(p_rid);
memdelete(reflection_probe);
return true;
} else if (lightmap_capture_data_owner.owns(p_rid)) {
// delete the texture
LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get_or_null(p_rid);
lightmap_capture->instance_remove_deps();
lightmap_capture_data_owner.free(p_rid);
memdelete(lightmap_capture);
return true;
} else if (canvas_occluder_owner.owns(p_rid)) {
CanvasOccluder *co = canvas_occluder_owner.get_or_null(p_rid);
if (co->index_id) {
glDeleteBuffers(1, &co->index_id);
}
if (co->vertex_id) {
glDeleteBuffers(1, &co->vertex_id);
}
canvas_occluder_owner.free(p_rid);
memdelete(co);
return true;
} else if (canvas_light_shadow_owner.owns(p_rid)) {
CanvasLightShadow *cls = canvas_light_shadow_owner.get_or_null(p_rid);
glDeleteFramebuffers(1, &cls->fbo);
glDeleteRenderbuffers(1, &cls->depth);
glDeleteTextures(1, &cls->distance);
canvas_light_shadow_owner.free(p_rid);
memdelete(cls);
return true;
}
*/
} }
/* DEPENDENCIES */ /* DEPENDENCIES */
@ -207,6 +176,12 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance
} else if (LightStorage::get_singleton()->owns_light(p_base)) { } else if (LightStorage::get_singleton()->owns_light(p_base)) {
Light *l = LightStorage::get_singleton()->get_light(p_base); Light *l = LightStorage::get_singleton()->get_light(p_base);
p_instance->update_dependency(&l->dependency); p_instance->update_dependency(&l->dependency);
} else if (ParticlesStorage::get_singleton()->owns_particles(p_base)) {
Dependency *dependency = ParticlesStorage::get_singleton()->particles_get_dependency(p_base);
p_instance->update_dependency(dependency);
} else if (ParticlesStorage::get_singleton()->owns_particles_collision(p_base)) {
Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
p_instance->update_dependency(dependency);
} }
} }

View File

@ -20,6 +20,7 @@ class GLES3HeaderStruct:
self.texunit_names = [] self.texunit_names = []
self.ubos = [] self.ubos = []
self.ubo_names = [] self.ubo_names = []
self.feedbacks = []
self.vertex_included_files = [] self.vertex_included_files = []
self.fragment_included_files = [] self.fragment_included_files = []
@ -168,6 +169,20 @@ def include_file_in_gles3_header(filename: str, header_data: GLES3HeaderStruct,
if not x in header_data.uniforms: if not x in header_data.uniforms:
header_data.uniforms += [x] header_data.uniforms += [x]
if (line.strip().find("out ") == 0 or line.strip().find("flat ") == 0) and line.find("tfb:") != -1:
uline = line.replace("flat ", "")
uline = uline.replace("out ", "")
uline = uline.replace("highp ", "")
uline = uline.replace(";", "")
uline = uline[uline.find(" ") :].strip()
if uline.find("//") != -1:
name, bind = uline.split("//")
if bind.find("tfb:") != -1:
name = name.strip()
bind = bind.replace("tfb:", "").strip()
header_data.feedbacks += [(name, bind)]
line = line.replace("\r", "") line = line.replace("\r", "")
line = line.replace("\n", "") line = line.replace("\n", "")
@ -240,11 +255,11 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
defspec |= 1 << i defspec |= 1 << i
fd.write( fd.write(
"\t_FORCE_INLINE_ void version_bind_shader(RID p_version,ShaderVariant p_variant" "\t_FORCE_INLINE_ bool version_bind_shader(RID p_version,ShaderVariant p_variant"
+ defvariant + defvariant
+ ",uint64_t p_specialization=" + ",uint64_t p_specialization="
+ str(defspec) + str(defspec)
+ ") { _version_bind_shader(p_version,p_variant,p_specialization); }\n\n" + ") { return _version_bind_shader(p_version,p_variant,p_specialization); }\n\n"
) )
if header_data.uniforms: if header_data.uniforms:
@ -278,7 +293,7 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
+ defvariant + defvariant
+ ",uint64_t p_specialization=" + ",uint64_t p_specialization="
+ str(defspec) + str(defspec)
+ ") { _FU glUniform1i(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),p_value); }\n\n" + ") { _FU glUniform1ui(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),p_value); }\n\n"
) )
fd.write( fd.write(
"\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, int8_t p_value,RID p_version,ShaderVariant p_variant" "\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, int8_t p_value,RID p_version,ShaderVariant p_variant"
@ -292,7 +307,7 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
+ defvariant + defvariant
+ ",uint64_t p_specialization=" + ",uint64_t p_specialization="
+ str(defspec) + str(defspec)
+ ") { _FU glUniform1i(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),p_value); }\n\n" + ") { _FU glUniform1ui(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),p_value); }\n\n"
) )
fd.write( fd.write(
"\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, int16_t p_value,RID p_version,ShaderVariant p_variant" "\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, int16_t p_value,RID p_version,ShaderVariant p_variant"
@ -306,7 +321,7 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
+ defvariant + defvariant
+ ",uint64_t p_specialization=" + ",uint64_t p_specialization="
+ str(defspec) + str(defspec)
+ ") { _FU glUniform1i(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),p_value); }\n\n" + ") { _FU glUniform1ui(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),p_value); }\n\n"
) )
fd.write( fd.write(
"\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, int32_t p_value,RID p_version,ShaderVariant p_variant" "\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, int32_t p_value,RID p_version,ShaderVariant p_variant"
@ -497,6 +512,8 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
else: else:
fd.write("\t\tstatic UBOPair *_ubo_pairs=nullptr;\n") fd.write("\t\tstatic UBOPair *_ubo_pairs=nullptr;\n")
specializations_found = []
if header_data.specialization_names: if header_data.specialization_names:
fd.write("\t\tstatic Specialization _spec_pairs[]={\n") fd.write("\t\tstatic Specialization _spec_pairs[]={\n")
for i in range(len(header_data.specialization_names)): for i in range(len(header_data.specialization_names)):
@ -507,10 +524,30 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
defval = "false" defval = "false"
fd.write('\t\t\t{"' + header_data.specialization_names[i] + '",' + defval + "},\n") fd.write('\t\t\t{"' + header_data.specialization_names[i] + '",' + defval + "},\n")
specializations_found.append(header_data.specialization_names[i])
fd.write("\t\t};\n\n") fd.write("\t\t};\n\n")
else: else:
fd.write("\t\tstatic Specialization *_spec_pairs=nullptr;\n") fd.write("\t\tstatic Specialization *_spec_pairs=nullptr;\n")
feedback_count = 0
if header_data.feedbacks:
fd.write("\t\tstatic const Feedback _feedbacks[]={\n")
for x in header_data.feedbacks:
name = x[0]
spec = x[1]
if spec in specializations_found:
fd.write('\t\t\t{"' + name + '",' + str(1 << specializations_found.index(spec)) + "},\n")
else:
fd.write('\t\t\t{"' + name + '",0},\n')
feedback_count += 1
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic const Feedback* _feedbacks=nullptr;\n")
fd.write("\t\tstatic const char _vertex_code[]={\n") fd.write("\t\tstatic const char _vertex_code[]={\n")
for x in header_data.vertex_lines: for x in header_data.vertex_lines:
for c in x: for c in x:
@ -535,6 +572,8 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
+ ",_uniform_strings," + ",_uniform_strings,"
+ str(len(header_data.ubos)) + str(len(header_data.ubos))
+ ",_ubo_pairs," + ",_ubo_pairs,"
+ str(feedback_count)
+ ",_feedbacks,"
+ str(len(header_data.texunits)) + str(len(header_data.texunits))
+ ",_texunit_pairs," + ",_texunit_pairs,"
+ str(len(header_data.specialization_names)) + str(len(header_data.specialization_names))

View File

@ -299,10 +299,6 @@ bool GPUParticles2D::get_interpolate() const {
PackedStringArray GPUParticles2D::get_configuration_warnings() const { PackedStringArray GPUParticles2D::get_configuration_warnings() const {
PackedStringArray warnings = Node2D::get_configuration_warnings(); PackedStringArray warnings = Node2D::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."));
}
if (process_material.is_null()) { if (process_material.is_null()) {
warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted.")); warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else { } else {

View File

@ -64,7 +64,7 @@ private:
#endif #endif
Ref<Material> process_material; Ref<Material> process_material;
DrawOrder draw_order; DrawOrder draw_order = DRAW_ORDER_LIFETIME;
Ref<Texture2D> texture; Ref<Texture2D> texture;

View File

@ -272,10 +272,6 @@ bool GPUParticles3D::get_interpolate() const {
PackedStringArray GPUParticles3D::get_configuration_warnings() const { PackedStringArray GPUParticles3D::get_configuration_warnings() const {
PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings(); PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."));
}
bool meshes_found = false; bool meshes_found = false;
bool anim_material_found = false; bool anim_material_found = false;

View File

@ -82,7 +82,7 @@ private:
Ref<Material> process_material; Ref<Material> process_material;
DrawOrder draw_order; DrawOrder draw_order = DRAW_ORDER_INDEX;
Vector<Ref<Mesh>> draw_passes; Vector<Ref<Mesh>> draw_passes;
Ref<Skin> skin; Ref<Skin> skin;

View File

@ -89,8 +89,6 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_instance) override {} virtual void particles_add_collision(RID p_particles, RID p_instance) override {}
virtual void particles_remove_collision(RID p_particles, RID p_instance) override {} virtual void particles_remove_collision(RID p_particles, RID p_instance) override {}
virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override {}
virtual void update_particles() override {} virtual void update_particles() override {}
/* PARTICLES COLLISION */ /* PARTICLES COLLISION */
@ -111,7 +109,6 @@ public:
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {} virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {}
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); } virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); }
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; } virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); }
virtual RID particles_collision_instance_create(RID p_collision) override { return RID(); } virtual RID particles_collision_instance_create(RID p_collision) override { return RID(); }
virtual void particles_collision_instance_free(RID p_rid) override {} virtual void particles_collision_instance_free(RID p_rid) override {}

View File

@ -1027,6 +1027,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
uniforms.push_back(u); uniforms.push_back(u);
} }
p_particles->collision_textures_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 2); p_particles->collision_textures_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 2);
p_particles->collision_heightmap_texture = collision_heightmap_texture;
} }
} }

View File

@ -54,8 +54,7 @@ private:
float velocity[3]; float velocity[3];
uint32_t active; uint32_t active;
float color[4]; float color[4];
float custom[3]; float custom[4];
float lifetime;
}; };
struct ParticlesFrameParams { struct ParticlesFrameParams {
@ -127,9 +126,6 @@ private:
Collider colliders[MAX_COLLIDERS]; Collider colliders[MAX_COLLIDERS];
}; };
struct ParticleEmissionBufferData {
};
struct ParticleEmissionBuffer { struct ParticleEmissionBuffer {
struct Data { struct Data {
float xform[16]; float xform[16];
@ -412,7 +408,7 @@ public:
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); } bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
virtual RID particles_allocate() override; virtual RID particles_allocate() override;
virtual void particles_initialize(RID p_particles_collision) override; virtual void particles_initialize(RID p_rid) override;
virtual void particles_free(RID p_rid) override; virtual void particles_free(RID p_rid) override;
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override; virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
@ -519,7 +515,7 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) override; virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) override;
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) override; virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) override;
virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override; void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture);
virtual void update_particles() override; virtual void update_particles() override;
@ -546,7 +542,7 @@ public:
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override; virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override;
Vector3 particles_collision_get_extents(RID p_particles_collision) const; Vector3 particles_collision_get_extents(RID p_particles_collision) const;
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override; virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
Dependency *particles_collision_get_dependency(RID p_particles) const; Dependency *particles_collision_get_dependency(RID p_particles) const;

View File

@ -94,8 +94,6 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0; virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0;
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0; virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0;
virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) = 0;
virtual void update_particles() = 0; virtual void update_particles() = 0;
/* PARTICLES COLLISION */ /* PARTICLES COLLISION */
@ -116,7 +114,6 @@ public:
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0; virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0;
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0;
//used from 2D and 3D //used from 2D and 3D
virtual RID particles_collision_instance_create(RID p_collision) = 0; virtual RID particles_collision_instance_create(RID p_collision) = 0;

View File

@ -18,7 +18,7 @@ public:
DISABLE_LIGHTING=1, DISABLE_LIGHTING=1,
}; };
_FORCE_INLINE_ void version_bind_shader(RID p_version,ShaderVariant p_variant,uint64_t p_specialization=0) { _version_bind_shader(p_version,p_variant,p_specialization); } _FORCE_INLINE_ bool version_bind_shader(RID p_version,ShaderVariant p_variant,uint64_t p_specialization=0) { return _version_bind_shader(p_version,p_variant,p_specialization); }
protected: protected:
@ -35,13 +35,14 @@ protected:
{"DISABLE_LIGHTING",false}, {"DISABLE_LIGHTING",false},
}; };
static const Feedback* _feedbacks=nullptr;
static const char _vertex_code[]={ static const char _vertex_code[]={
10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,104,105,103,104,112,32,118,101,99,51,32,118,101,114,116,101,120,59,10,10,111,117,116,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,32,61,32,118,101,99,52,40,118,101,114,116,101,120,46,120,44,49,44,48,44,49,41,59,10,125,10,10, 0}; 10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,104,105,103,104,112,32,118,101,99,51,32,118,101,114,116,101,120,59,10,10,111,117,116,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,32,61,32,118,101,99,52,40,118,101,114,116,101,120,46,120,44,49,44,48,44,49,41,59,10,125,10,10, 0};
static const char _fragment_code[]={ static const char _fragment_code[]={
10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,105,110,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,104,105,103,104,112,32,102,108,111,97,116,32,100,101,112,116,104,32,61,32,40,40,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,122,32,47,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,119,41,32,43,32,49,46,48,41,59,10,9,102,114,97,103,95,99,111,108,111,114,32,61,32,118,101,99,52,40,100,101,112,116,104,41,59,10,125,10, 0}; 10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,105,110,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,104,105,103,104,112,32,102,108,111,97,116,32,100,101,112,116,104,32,61,32,40,40,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,122,32,47,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,119,41,32,43,32,49,46,48,41,59,10,9,102,114,97,103,95,99,111,108,111,114,32,61,32,118,101,99,52,40,100,101,112,116,104,41,59,10,125,10, 0};
_setup(_vertex_code,_fragment_code,"VertexFragmentShaderGLES3",0,_uniform_strings,0,_ubo_pairs,0,_texunit_pairs,1,_spec_pairs,1,_variant_defines); _setup(_vertex_code,_fragment_code,"VertexFragmentShaderGLES3",0,_uniform_strings,0,_ubo_pairs,0,_feedbacks,0,_texunit_pairs,1,_spec_pairs,1,_variant_defines);
} }
}; };

View File

@ -31,6 +31,7 @@
"texunit_names": [], "texunit_names": [],
"ubos": [], "ubos": [],
"ubo_names": [], "ubo_names": [],
"feedbacks": [],
"vertex_included_files": [], "vertex_included_files": [],
"fragment_included_files": [], "fragment_included_files": [],
"reading": "fragment", "reading": "fragment",