Merge pull request #68426 from clayjohn/GLES3-particles
Add GPUParticles to the OpenGL3 renderer.
This commit is contained in:
commit
5f78f24b08
|
@ -115,13 +115,21 @@ CopyEffects::~CopyEffects() {
|
|||
}
|
||||
|
||||
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);
|
||||
draw_screen_quad();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
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::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
|
||||
draw_screen_quad();
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "storage/config.h"
|
||||
#include "storage/material_storage.h"
|
||||
#include "storage/mesh_storage.h"
|
||||
#include "storage/particles_storage.h"
|
||||
#include "storage/texture_storage.h"
|
||||
|
||||
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;
|
||||
|
||||
_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) {
|
||||
|
@ -623,7 +624,10 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
|||
uint64_t specialization = 0;
|
||||
specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
|
||||
specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
|
||||
_bind_material(material_data, variant, specialization);
|
||||
bool success = _bind_material(material_data, variant, specialization);
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_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 *¤t_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;
|
||||
|
||||
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;
|
||||
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, state.instance_data_array[r_index].world);
|
||||
modulate = m->modulate;
|
||||
|
||||
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
|
||||
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
|
||||
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);
|
||||
if (instance_count > 1) {
|
||||
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
|
||||
}
|
||||
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
|
||||
|
||||
} 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;
|
||||
|
@ -1209,20 +1243,21 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
|||
case Item::Command::TYPE_MULTIMESH:
|
||||
case Item::Command::TYPE_PARTICLES: {
|
||||
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
|
||||
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
|
||||
RID mesh;
|
||||
RID mesh_instance;
|
||||
RID texture;
|
||||
uint32_t instance_count = 1;
|
||||
GLuint multimesh_buffer = 0;
|
||||
uint32_t multimesh_stride = 0;
|
||||
uint32_t multimesh_color_offset = 0;
|
||||
bool multimesh_uses_color = false;
|
||||
bool multimesh_uses_custom_data = false;
|
||||
GLuint instance_buffer = 0;
|
||||
uint32_t instance_stride = 0;
|
||||
uint32_t instance_color_offset = 0;
|
||||
bool instance_uses_color = false;
|
||||
bool instance_uses_custom_data = false;
|
||||
|
||||
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);
|
||||
mesh = m->mesh;
|
||||
mesh_instance = m->mesh_instance;
|
||||
|
||||
} 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);
|
||||
RID multimesh = mm->multimesh;
|
||||
|
@ -1238,13 +1273,41 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
|||
break;
|
||||
}
|
||||
|
||||
multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
|
||||
multimesh_stride = mesh_storage->multimesh_get_stride(multimesh);
|
||||
multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
|
||||
multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
|
||||
multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
|
||||
instance_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
|
||||
instance_stride = mesh_storage->multimesh_get_stride(multimesh);
|
||||
instance_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
|
||||
instance_uses_color = mesh_storage->multimesh_uses_colors(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) {
|
||||
// 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());
|
||||
|
@ -1277,17 +1340,17 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
|||
|
||||
if (instance_count > 1) {
|
||||
// Bind instance buffers.
|
||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
|
||||
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);
|
||||
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);
|
||||
|
||||
if (multimesh_uses_color || multimesh_uses_custom_data) {
|
||||
if (instance_uses_color || instance_uses_custom_data) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1361,17 +1424,17 @@ void RasterizerCanvasGLES3::_new_batch(bool &r_batch_broken, uint32_t &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->shader_data->version.is_valid() && p_material_data->shader_data->valid) {
|
||||
// Bind uniform buffer and textures
|
||||
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 {
|
||||
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 {
|
||||
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;
|
||||
|
||||
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++) {
|
||||
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;
|
||||
|
||||
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.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);
|
||||
|
||||
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::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);
|
||||
data.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
|
||||
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
|
||||
|
||||
shadow_render.shader.initialize();
|
||||
shadow_render.shader_version = shadow_render.shader.version_create();
|
||||
|
|
|
@ -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 _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 *¤t_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 *¤t_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 _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 _add_to_batch(uint32_t &r_index, bool &r_batch_broken);
|
||||
void _allocate_instance_data_buffer();
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "servers/rendering/rendering_server_globals.h"
|
||||
#include "storage/config.h"
|
||||
#include "storage/mesh_storage.h"
|
||||
#include "storage/particles_storage.h"
|
||||
#include "storage/texture_storage.h"
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
@ -50,6 +51,9 @@ RenderGeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_bas
|
|||
|
||||
ginstance->data->base = p_base;
|
||||
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();
|
||||
|
||||
|
@ -314,6 +318,8 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface(GeometryInstanceGLES3
|
|||
|
||||
void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_geometry_instance) {
|
||||
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
|
||||
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
|
||||
|
||||
GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
|
||||
|
||||
if (ginstance->data->dirty_dependencies) {
|
||||
|
@ -361,6 +367,26 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
|
|||
|
||||
} break;
|
||||
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;
|
||||
|
||||
default: {
|
||||
|
@ -382,9 +408,17 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
|
|||
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) {
|
||||
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) {
|
||||
}
|
||||
|
||||
|
@ -751,12 +785,16 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
|
|||
sky_transform.invert();
|
||||
sky_transform = p_transform.basis * sky_transform;
|
||||
|
||||
GLES3::MaterialStorage::get_singleton()->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);
|
||||
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);
|
||||
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);
|
||||
bool success = material_storage->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
GLES3::MaterialStorage::get_singleton()->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);
|
||||
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::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
|
||||
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, 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);
|
||||
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);
|
||||
|
||||
|
@ -864,7 +905,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
|
|||
|
||||
for (int i = 0; i < 6; 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);
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
glClearDepth(1.0f);
|
||||
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());
|
||||
|
||||
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.
|
||||
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))) {
|
||||
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
|
||||
spec_constant_base_flags |= SceneShaderGLES3::DISABLE_FOG;
|
||||
}
|
||||
}
|
||||
// Render Opaque Objects.
|
||||
|
@ -1947,6 +1994,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
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) {
|
||||
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::TextureStorage *texture_storage = GLES3::TextureStorage::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 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 = 0;
|
||||
uint32_t base_spec_constants = p_params->spec_constant_base_flags;
|
||||
|
||||
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) {
|
||||
|
@ -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));
|
||||
if (sky && sky->radiance != 0) {
|
||||
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);
|
||||
}
|
||||
|
@ -2157,7 +2204,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||
}
|
||||
|
||||
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) {
|
||||
// Bind index each time so we can use LODs
|
||||
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;
|
||||
if (inst->instance_count > 0) {
|
||||
// Will need to use instancing to draw (either MultiMesh or Particles).
|
||||
instance_variant = SceneShaderGLES3::ShaderVariant(1 + int(shader_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;
|
||||
if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
|
||||
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);
|
||||
if (inst->instance_count > 0) {
|
||||
// Using MultiMesh.
|
||||
// Using MultiMesh or Particles.
|
||||
// Bind instance buffers.
|
||||
|
||||
GLuint multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(inst->data->base);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
|
||||
uint32_t multimesh_stride = mesh_storage->multimesh_get_stride(inst->data->base);
|
||||
GLuint instance_buffer = 0;
|
||||
uint32_t stride = 0;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
glEnableVertexAttribArray(14);
|
||||
glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 8));
|
||||
glVertexAttribDivisor(14, 1);
|
||||
if (!(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D)) {
|
||||
glEnableVertexAttribArray(14);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
|
@ -2415,7 +2550,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
|
|||
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_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);
|
||||
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);
|
||||
|
@ -2455,7 +2590,6 @@ void fragment() {
|
|||
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n";
|
||||
material_storage->shaders.sky_shader.initialize(global_defines);
|
||||
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";
|
||||
material_storage->shaders.cubemap_filter_shader.initialize(global_defines);
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -85,16 +85,6 @@ enum SkyUniformLocation {
|
|||
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 {
|
||||
Ref<RenderSceneBuffersGLES3> render_buffers;
|
||||
bool transparent_bg = false;
|
||||
|
|
|
@ -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;
|
||||
|
||||
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_count = p_variant_count;
|
||||
feedbacks = p_feedback;
|
||||
feedback_count = p_feedback_count;
|
||||
|
||||
StringBuilder tohash;
|
||||
/*
|
||||
|
@ -339,9 +341,21 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
|
|||
glAttachShader(spec.id, spec.frag_id);
|
||||
glAttachShader(spec.id, spec.vert_id);
|
||||
|
||||
//for (int i = 0; i < attribute_pair_count; i++) {
|
||||
// glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
|
||||
//}
|
||||
// If feedback exists, set it up.
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -70,6 +70,11 @@ protected:
|
|||
bool default_value = false;
|
||||
};
|
||||
|
||||
struct Feedback {
|
||||
const char *name;
|
||||
uint64_t specialization;
|
||||
};
|
||||
|
||||
private:
|
||||
//versions
|
||||
CharString general_defines;
|
||||
|
@ -165,6 +170,8 @@ private:
|
|||
int uniform_count = 0;
|
||||
const UBOPair *ubo_pairs = nullptr;
|
||||
int ubo_count = 0;
|
||||
const Feedback *feedbacks;
|
||||
int feedback_count = 0;
|
||||
const TexUnitPair *texunit_pairs = nullptr;
|
||||
int texunit_pair_count = 0;
|
||||
int specialization_count = 0;
|
||||
|
@ -178,13 +185,13 @@ private:
|
|||
|
||||
protected:
|
||||
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) {
|
||||
ERR_FAIL_INDEX(p_variant, variant_count);
|
||||
_FORCE_INLINE_ bool _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) {
|
||||
ERR_FAIL_INDEX_V(p_variant, variant_count, false);
|
||||
|
||||
Version *version = version_owner.get_or_null(p_version);
|
||||
ERR_FAIL_COND(!version);
|
||||
ERR_FAIL_COND_V(!version, false);
|
||||
|
||||
if (version->variants.size() == 0) {
|
||||
_initialize_version(version); //may lack initialization
|
||||
|
@ -210,11 +217,12 @@ protected:
|
|||
|
||||
if (!spec || !spec->ok) {
|
||||
WARN_PRINT_ONCE("shader failed to compile, unable to bind shader.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
glUseProgram(spec->id);
|
||||
current_shader = spec;
|
||||
return true;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _version_get_uniform(int p_which, RID p_version, int p_variant, uint64_t p_specialization) {
|
||||
|
|
|
@ -19,3 +19,5 @@ if "GLES3_GLSL" in env["BUILDERS"]:
|
|||
env.GLES3_GLSL("cubemap_filter.glsl")
|
||||
env.GLES3_GLSL("canvas_occlusion.glsl")
|
||||
env.GLES3_GLSL("canvas_sdf.glsl")
|
||||
env.GLES3_GLSL("particles.glsl")
|
||||
env.GLES3_GLSL("particles_copy.glsl")
|
||||
|
|
|
@ -31,7 +31,7 @@ uniform samplerCube source_cube; //texunit:0
|
|||
uniform int face_id;
|
||||
|
||||
#ifndef MODE_DIRECT_WRITE
|
||||
uniform int sample_count;
|
||||
uniform uint sample_count;
|
||||
uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT];
|
||||
uniform float weight;
|
||||
#endif
|
||||
|
@ -105,7 +105,7 @@ void main() {
|
|||
T[1] = cross(N, T[0]);
|
||||
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];
|
||||
vec3 L = T * sample_direction_mip.xyz;
|
||||
vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb;
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -197,7 +197,7 @@ out vec3 tangent_interp;
|
|||
out vec3 binormal_interp;
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_UNIFORMS_USED)
|
||||
#ifdef MATERIAL_UNIFORMS_USED
|
||||
|
||||
/* clang-format off */
|
||||
layout(std140) uniform MaterialUniforms { // ubo:3
|
||||
|
@ -366,7 +366,9 @@ void main() {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MODE_RENDER_DEPTH
|
||||
#include "tonemap_inc.glsl"
|
||||
#endif
|
||||
#include "stdlib_inc.glsl"
|
||||
|
||||
/* texture unit usage, N is max_texture_unity-N
|
||||
|
@ -428,7 +430,7 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1
|
|||
|
||||
/* Material Uniforms */
|
||||
|
||||
#if defined(MATERIAL_UNIFORMS_USED)
|
||||
#ifdef MATERIAL_UNIFORMS_USED
|
||||
|
||||
/* clang-format off */
|
||||
layout(std140) uniform MaterialUniforms { // ubo:3
|
||||
|
@ -535,7 +537,7 @@ layout(std140) uniform OmniLightData { // ubo:5
|
|||
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
|
||||
};
|
||||
uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
|
||||
uniform int omni_light_count;
|
||||
uniform uint omni_light_count;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_LIGHT_SPOT
|
||||
|
@ -545,7 +547,7 @@ layout(std140) uniform SpotLightData { // ubo:6
|
|||
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
|
||||
};
|
||||
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
|
||||
uniform int spot_light_count;
|
||||
uniform uint spot_light_count;
|
||||
#endif
|
||||
|
||||
#ifdef USE_ADDITIVE_LIGHTING
|
||||
|
@ -1188,7 +1190,7 @@ void main() {
|
|||
#endif //!DISABLE_LIGHT_DIRECTIONAL
|
||||
|
||||
#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) {
|
||||
break;
|
||||
}
|
||||
|
@ -1211,7 +1213,7 @@ void main() {
|
|||
#endif // !DISABLE_LIGHT_OMNI
|
||||
|
||||
#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) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "material_storage.h"
|
||||
#include "particles_storage.h"
|
||||
#include "texture_storage.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_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_FOG] = nullptr;
|
||||
|
||||
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_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_FOG] = nullptr;
|
||||
|
||||
|
@ -1613,32 +1614,32 @@ MaterialStorage::MaterialStorage() {
|
|||
|
||||
{
|
||||
// Setup Particles compiler
|
||||
/*
|
||||
ShaderCompiler::DefaultIdentifierActions actions;
|
||||
|
||||
actions.renames["COLOR"] = "PARTICLE.color";
|
||||
actions.renames["VELOCITY"] = "PARTICLE.velocity";
|
||||
ShaderCompiler::DefaultIdentifierActions actions;
|
||||
|
||||
actions.renames["COLOR"] = "out_color";
|
||||
actions.renames["VELOCITY"] = "out_velocity_flags.xyz";
|
||||
//actions.renames["MASS"] = "mass"; ?
|
||||
actions.renames["ACTIVE"] = "particle_active";
|
||||
actions.renames["RESTART"] = "restart";
|
||||
actions.renames["CUSTOM"] = "PARTICLE.custom";
|
||||
for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) {
|
||||
actions.renames["CUSTOM"] = "out_custom";
|
||||
for (int i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
|
||||
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.renames["TRANSFORM"] = "PARTICLE.xform";
|
||||
actions.renames["TIME"] = "frame_history.data[0].time";
|
||||
actions.renames["TRANSFORM"] = "xform";
|
||||
actions.renames["TIME"] = "time";
|
||||
actions.renames["PI"] = _MKSTR(Math_PI);
|
||||
actions.renames["TAU"] = _MKSTR(Math_TAU);
|
||||
actions.renames["E"] = _MKSTR(Math_E);
|
||||
actions.renames["LIFETIME"] = "params.lifetime";
|
||||
actions.renames["LIFETIME"] = "lifetime";
|
||||
actions.renames["DELTA"] = "local_delta";
|
||||
actions.renames["NUMBER"] = "particle_number";
|
||||
actions.renames["INDEX"] = "index";
|
||||
//actions.renames["GRAVITY"] = "current_gravity";
|
||||
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
|
||||
actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
|
||||
actions.renames["EMISSION_TRANSFORM"] = "emission_transform";
|
||||
actions.renames["RANDOM_SEED"] = "random_seed";
|
||||
actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
|
||||
actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
|
||||
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["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_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;
|
||||
if (mode_string == "canvas_item") {
|
||||
new_mode = RS::SHADER_CANVAS_ITEM;
|
||||
//} else if (mode_string == "particles") {
|
||||
// new_mode = RS::SHADER_PARTICLES;
|
||||
} else if (mode_string == "particles") {
|
||||
new_mode = RS::SHADER_PARTICLES;
|
||||
} else if (mode_string == "spatial") {
|
||||
new_mode = RS::SHADER_SPATIAL;
|
||||
} 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);
|
||||
|
||||
shader->path_hint = p_path;
|
||||
if (shader->data) {
|
||||
shader->data->set_path_hint(p_path);
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
void CanvasShaderData::set_path_hint(const String &p_path) {
|
||||
path = p_path;
|
||||
}
|
||||
|
||||
void CanvasShaderData::set_code(const String &p_code) {
|
||||
// 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) {
|
||||
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() {
|
||||
|
@ -3043,6 +3043,10 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// SKY SHADER
|
||||
|
||||
void SkyShaderData::set_path_hint(const String &p_path) {
|
||||
path = p_path;
|
||||
}
|
||||
|
||||
void SkyShaderData::set_code(const String &p_code) {
|
||||
//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) {
|
||||
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() {
|
||||
|
@ -3286,6 +3290,10 @@ void SkyMaterialData::bind_uniforms() {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Scene SHADER
|
||||
|
||||
void SceneShaderData::set_path_hint(const String &p_path) {
|
||||
path = p_path;
|
||||
}
|
||||
|
||||
void SceneShaderData::set_code(const String &p_code) {
|
||||
//compile
|
||||
|
||||
|
@ -3592,7 +3600,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) {
|
||||
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() {
|
||||
|
@ -3625,4 +3633,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
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
#include "../shaders/canvas.glsl.gen.h"
|
||||
#include "../shaders/cubemap_filter.glsl.gen.h"
|
||||
#include "../shaders/particles.glsl.gen.h"
|
||||
#include "../shaders/scene.glsl.gen.h"
|
||||
#include "../shaders/sky.glsl.gen.h"
|
||||
|
||||
|
@ -53,6 +54,7 @@ namespace GLES3 {
|
|||
|
||||
struct ShaderData {
|
||||
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 get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
|
||||
|
||||
|
@ -165,6 +167,7 @@ struct CanvasShaderData : public ShaderData {
|
|||
bool uses_time = false;
|
||||
|
||||
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;
|
||||
|
@ -216,6 +219,7 @@ struct SkyShaderData : public ShaderData {
|
|||
bool uses_light;
|
||||
|
||||
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;
|
||||
|
@ -339,6 +343,7 @@ struct SceneShaderData : public ShaderData {
|
|||
uint32_t index = 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;
|
||||
|
@ -370,6 +375,62 @@ struct SceneMaterialData : public MaterialData {
|
|||
|
||||
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 */
|
||||
struct GlobalShaderUniforms {
|
||||
enum {
|
||||
|
@ -506,6 +567,7 @@ public:
|
|||
SkyShaderGLES3 sky_shader;
|
||||
SceneShaderGLES3 scene_shader;
|
||||
CubemapFilterShaderGLES3 cubemap_filter_shader;
|
||||
ParticlesShaderGLES3 particles_process_shader;
|
||||
|
||||
ShaderCompiler compiler_canvas;
|
||||
ShaderCompiler compiler_scene;
|
||||
|
|
|
@ -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->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;
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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 {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
ERR_FAIL_COND_V(!s, 0);
|
||||
|
||||
int32_t current_lod = -1;
|
||||
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 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) {
|
||||
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
||||
ERR_FAIL_COND(!mi);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -33,25 +33,283 @@
|
|||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "../shaders/particles_copy.glsl.gen.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/self_list.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 {
|
||||
|
||||
enum ParticlesUniformLocation {
|
||||
PARTICLES_FRAME_UNIFORM_LOCATION,
|
||||
PARTICLES_GLOBALS_UNIFORM_LOCATION,
|
||||
PARTICLES_MATERIAL_UNIFORM_LOCATION,
|
||||
};
|
||||
|
||||
class ParticlesStorage : public RendererParticlesStorage {
|
||||
private:
|
||||
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:
|
||||
static ParticlesStorage *get_singleton();
|
||||
|
||||
ParticlesStorage();
|
||||
virtual ~ParticlesStorage();
|
||||
|
||||
bool free(RID p_rid);
|
||||
|
||||
/* PARTICLES */
|
||||
|
||||
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
|
||||
|
||||
virtual RID particles_allocate() override;
|
||||
virtual void particles_initialize(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_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 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 */
|
||||
bool owns_particles_collision(RID p_rid) { return particles_collision_owner.owns(p_rid); }
|
||||
|
||||
virtual RID particles_collision_allocate() 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_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;
|
||||
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
|
||||
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 void particles_collision_instance_free(RID p_rid) override;
|
||||
|
|
|
@ -647,7 +647,7 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
|
|||
texture.height = p_image->get_height();
|
||||
texture.alloc_width = texture.width;
|
||||
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.type = Texture::TYPE_2D;
|
||||
texture.target = GL_TEXTURE_2D;
|
||||
|
@ -2215,7 +2215,11 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) {
|
|||
|
||||
// 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::SIZE, size, 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);
|
||||
|
||||
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::SIZE, size, 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
|
||||
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::SIZE, size, sdf_shader.shader_version, variant);
|
||||
sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
|
||||
|
|
|
@ -108,6 +108,10 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const {
|
|||
return RS::INSTANCE_LIGHT;
|
||||
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
|
||||
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;
|
||||
}
|
||||
|
@ -143,53 +147,18 @@ bool Utilities::free(RID p_rid) {
|
|||
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
|
||||
GLES3::LightStorage::get_singleton()->lightmap_free(p_rid);
|
||||
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 {
|
||||
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 */
|
||||
|
@ -207,6 +176,12 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance
|
|||
} else if (LightStorage::get_singleton()->owns_light(p_base)) {
|
||||
Light *l = LightStorage::get_singleton()->get_light(p_base);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class GLES3HeaderStruct:
|
|||
self.texunit_names = []
|
||||
self.ubos = []
|
||||
self.ubo_names = []
|
||||
self.feedbacks = []
|
||||
|
||||
self.vertex_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:
|
||||
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("\n", "")
|
||||
|
||||
|
@ -240,11 +255,11 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
|
|||
defspec |= 1 << i
|
||||
|
||||
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
|
||||
+ ",uint64_t p_specialization="
|
||||
+ 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:
|
||||
|
@ -278,7 +293,7 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
|
|||
+ defvariant
|
||||
+ ",uint64_t p_specialization="
|
||||
+ 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(
|
||||
"\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
|
||||
+ ",uint64_t p_specialization="
|
||||
+ 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(
|
||||
"\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
|
||||
+ ",uint64_t p_specialization="
|
||||
+ 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(
|
||||
"\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:
|
||||
fd.write("\t\tstatic UBOPair *_ubo_pairs=nullptr;\n")
|
||||
|
||||
specializations_found = []
|
||||
|
||||
if header_data.specialization_names:
|
||||
fd.write("\t\tstatic Specialization _spec_pairs[]={\n")
|
||||
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"
|
||||
|
||||
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")
|
||||
else:
|
||||
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")
|
||||
for x in header_data.vertex_lines:
|
||||
for c in x:
|
||||
|
@ -535,6 +572,8 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
|
|||
+ ",_uniform_strings,"
|
||||
+ str(len(header_data.ubos))
|
||||
+ ",_ubo_pairs,"
|
||||
+ str(feedback_count)
|
||||
+ ",_feedbacks,"
|
||||
+ str(len(header_data.texunits))
|
||||
+ ",_texunit_pairs,"
|
||||
+ str(len(header_data.specialization_names))
|
||||
|
|
|
@ -299,10 +299,6 @@ bool GPUParticles2D::get_interpolate() const {
|
|||
PackedStringArray GPUParticles2D::get_configuration_warnings() const {
|
||||
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()) {
|
||||
warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted."));
|
||||
} else {
|
||||
|
|
|
@ -64,7 +64,7 @@ private:
|
|||
#endif
|
||||
Ref<Material> process_material;
|
||||
|
||||
DrawOrder draw_order;
|
||||
DrawOrder draw_order = DRAW_ORDER_LIFETIME;
|
||||
|
||||
Ref<Texture2D> texture;
|
||||
|
||||
|
|
|
@ -272,10 +272,6 @@ bool GPUParticles3D::get_interpolate() const {
|
|||
PackedStringArray GPUParticles3D::get_configuration_warnings() const {
|
||||
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 anim_material_found = false;
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ private:
|
|||
|
||||
Ref<Material> process_material;
|
||||
|
||||
DrawOrder draw_order;
|
||||
DrawOrder draw_order = DRAW_ORDER_INDEX;
|
||||
|
||||
Vector<Ref<Mesh>> draw_passes;
|
||||
Ref<Skin> skin;
|
||||
|
|
|
@ -89,8 +89,6 @@ public:
|
|||
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_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 {}
|
||||
|
||||
/* 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 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 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 void particles_collision_instance_free(RID p_rid) override {}
|
||||
|
|
|
@ -1027,6 +1027,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
|
|||
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_heightmap_texture = collision_heightmap_texture;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,8 +54,7 @@ private:
|
|||
float velocity[3];
|
||||
uint32_t active;
|
||||
float color[4];
|
||||
float custom[3];
|
||||
float lifetime;
|
||||
float custom[4];
|
||||
};
|
||||
|
||||
struct ParticlesFrameParams {
|
||||
|
@ -127,9 +126,6 @@ private:
|
|||
Collider colliders[MAX_COLLIDERS];
|
||||
};
|
||||
|
||||
struct ParticleEmissionBufferData {
|
||||
};
|
||||
|
||||
struct ParticleEmissionBuffer {
|
||||
struct Data {
|
||||
float xform[16];
|
||||
|
@ -412,7 +408,7 @@ public:
|
|||
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
|
||||
|
||||
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_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_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;
|
||||
|
||||
|
@ -546,7 +542,7 @@ public:
|
|||
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 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;
|
||||
|
||||
|
|
|
@ -94,8 +94,6 @@ public:
|
|||
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_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;
|
||||
|
||||
/* 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 AABB particles_collision_get_aabb(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
|
||||
virtual RID particles_collision_instance_create(RID p_collision) = 0;
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
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:
|
||||
|
||||
|
@ -35,13 +35,14 @@ protected:
|
|||
{"DISABLE_LIGHTING",false},
|
||||
};
|
||||
|
||||
static const Feedback* _feedbacks=nullptr;
|
||||
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};
|
||||
|
||||
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};
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
"texunit_names": [],
|
||||
"ubos": [],
|
||||
"ubo_names": [],
|
||||
"feedbacks": [],
|
||||
"vertex_included_files": [],
|
||||
"fragment_included_files": [],
|
||||
"reading": "fragment",
|
||||
|
|
Loading…
Reference in New Issue