Merge pull request #48617 from reduz/gpu-particles-2d
Fixes multiple missing 2D engine bits
This commit is contained in:
commit
048abb50aa
|
@ -369,6 +369,7 @@ void GPUParticles2D::_bind_methods() {
|
|||
|
||||
GPUParticles2D::GPUParticles2D() {
|
||||
particles = RS::get_singleton()->particles_create();
|
||||
RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_2D);
|
||||
|
||||
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
|
||||
set_emitting(true);
|
||||
|
|
|
@ -302,17 +302,18 @@ void Polygon2D::_notification(int p_what) {
|
|||
colors.write[i] = color_r[i];
|
||||
}
|
||||
} else {
|
||||
colors.push_back(color);
|
||||
colors.resize(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
colors.write[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<int> index_array;
|
||||
|
||||
if (invert || polygons.size() == 0) {
|
||||
Vector<int> indices = Geometry2D::triangulate_polygon(points);
|
||||
if (indices.size()) {
|
||||
RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1);
|
||||
}
|
||||
index_array = Geometry2D::triangulate_polygon(points);
|
||||
} else {
|
||||
//draw individual polygons
|
||||
Vector<int> total_indices;
|
||||
for (int i = 0; i < polygons.size(); i++) {
|
||||
Vector<int> src_indices = polygons[i];
|
||||
int ic = src_indices.size();
|
||||
|
@ -333,18 +334,38 @@ void Polygon2D::_notification(int p_what) {
|
|||
int ic2 = indices.size();
|
||||
const int *r2 = indices.ptr();
|
||||
|
||||
int bic = total_indices.size();
|
||||
total_indices.resize(bic + ic2);
|
||||
int *w2 = total_indices.ptrw();
|
||||
int bic = index_array.size();
|
||||
index_array.resize(bic + ic2);
|
||||
int *w2 = index_array.ptrw();
|
||||
|
||||
for (int j = 0; j < ic2; j++) {
|
||||
w2[j + bic] = r[r2[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total_indices.size()) {
|
||||
RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), total_indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
|
||||
RS::get_singleton()->mesh_clear(mesh);
|
||||
|
||||
if (index_array.size()) {
|
||||
Array arr;
|
||||
arr.resize(RS::ARRAY_MAX);
|
||||
arr[RS::ARRAY_VERTEX] = points;
|
||||
if (uvs.size() == points.size()) {
|
||||
arr[RS::ARRAY_TEX_UV] = uvs;
|
||||
}
|
||||
if (colors.size() == points.size()) {
|
||||
arr[RS::ARRAY_COLOR] = colors;
|
||||
}
|
||||
|
||||
if (bones.size() == points.size() * 4) {
|
||||
arr[RS::ARRAY_BONES] = bones;
|
||||
arr[RS::ARRAY_WEIGHTS] = weights;
|
||||
}
|
||||
|
||||
arr[RS::ARRAY_INDEX] = index_array;
|
||||
|
||||
RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
|
||||
RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(), texture.is_valid() ? texture->get_rid() : RID());
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -655,4 +676,9 @@ void Polygon2D::_bind_methods() {
|
|||
}
|
||||
|
||||
Polygon2D::Polygon2D() {
|
||||
mesh = RS::get_singleton()->mesh_create();
|
||||
}
|
||||
|
||||
Polygon2D::~Polygon2D() {
|
||||
RS::get_singleton()->free(mesh);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ class Polygon2D : public Node2D {
|
|||
|
||||
void _skeleton_bone_setup_changed();
|
||||
|
||||
RID mesh;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
@ -149,6 +151,7 @@ public:
|
|||
NodePath get_skeleton() const;
|
||||
|
||||
Polygon2D();
|
||||
~Polygon2D();
|
||||
};
|
||||
|
||||
#endif // POLYGON_2D_H
|
||||
|
|
|
@ -613,6 +613,7 @@ void GPUParticles3D::_bind_methods() {
|
|||
|
||||
GPUParticles3D::GPUParticles3D() {
|
||||
particles = RS::get_singleton()->particles_create();
|
||||
RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_3D);
|
||||
set_base(particles);
|
||||
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
|
||||
set_emitting(true);
|
||||
|
|
|
@ -923,10 +923,15 @@ void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transfo
|
|||
void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) {
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
ERR_FAIL_COND(!p_mesh.is_valid());
|
||||
|
||||
Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>();
|
||||
ERR_FAIL_COND(!m);
|
||||
m->mesh = p_mesh;
|
||||
if (canvas_item->skeleton.is_valid()) {
|
||||
m->mesh_instance = RSG::storage->mesh_instance_create(p_mesh);
|
||||
RSG::storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton);
|
||||
}
|
||||
|
||||
m->texture = p_texture;
|
||||
|
||||
|
@ -996,8 +1001,30 @@ void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, boo
|
|||
void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
|
||||
if (canvas_item->skeleton == p_skeleton) {
|
||||
return;
|
||||
}
|
||||
canvas_item->skeleton = p_skeleton;
|
||||
|
||||
Item::Command *c = canvas_item->commands;
|
||||
|
||||
while (c) {
|
||||
if (c->type == Item::Command::TYPE_MESH) {
|
||||
Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c);
|
||||
if (canvas_item->skeleton.is_valid()) {
|
||||
if (cm->mesh_instance.is_null()) {
|
||||
cm->mesh_instance = RSG::storage->mesh_instance_create(cm->mesh);
|
||||
}
|
||||
RSG::storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton);
|
||||
} else {
|
||||
if (cm->mesh_instance.is_valid()) {
|
||||
RSG::storage->free(cm->mesh_instance);
|
||||
cm->mesh_instance = RID();
|
||||
}
|
||||
}
|
||||
}
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
|
||||
|
|
|
@ -246,10 +246,16 @@ public:
|
|||
RID mesh;
|
||||
Transform2D transform;
|
||||
Color modulate;
|
||||
RID mesh_instance;
|
||||
|
||||
RID texture;
|
||||
|
||||
CommandMesh() { type = TYPE_MESH; }
|
||||
~CommandMesh() {
|
||||
if (mesh_instance.is_valid()) {
|
||||
RendererStorage::base_singleton->free(mesh_instance);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct CommandMultiMesh : public Command {
|
||||
|
@ -262,7 +268,6 @@ public:
|
|||
|
||||
struct CommandParticles : public Command {
|
||||
RID particles;
|
||||
|
||||
RID texture;
|
||||
|
||||
CommandParticles() { type = TYPE_PARTICLES; }
|
||||
|
|
|
@ -705,286 +705,128 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
|
|||
case Item::Command::TYPE_MESH:
|
||||
case Item::Command::TYPE_MULTIMESH:
|
||||
case Item::Command::TYPE_PARTICLES: {
|
||||
ERR_PRINT("FIXME: Mesh, MultiMesh and Particles render commands are unimplemented currently, they need to be ported to the 4.0 rendering architecture.");
|
||||
#ifndef _MSC_VER
|
||||
#warning Item::Command types for Mesh, MultiMesh and Particles need to be implemented.
|
||||
#endif
|
||||
// See #if 0'ed code below to port from GLES3.
|
||||
} break;
|
||||
RID mesh;
|
||||
RID mesh_instance;
|
||||
RID texture;
|
||||
Color modulate(1, 1, 1, 1);
|
||||
float world_backup[6];
|
||||
int instance_count = 1;
|
||||
|
||||
#if 0
|
||||
case Item::Command::TYPE_MESH: {
|
||||
Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c);
|
||||
_set_texture_rect_mode(false);
|
||||
|
||||
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map);
|
||||
|
||||
if (texture) {
|
||||
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
world_backup[j] = push_constant.world[j];
|
||||
}
|
||||
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform);
|
||||
if (c->type == Item::Command::TYPE_MESH) {
|
||||
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
|
||||
mesh = m->mesh;
|
||||
mesh_instance = m->mesh_instance;
|
||||
texture = m->texture;
|
||||
modulate = m->modulate;
|
||||
_update_transform_2d_to_mat2x3(base_transform * m->transform, push_constant.world);
|
||||
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
|
||||
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
|
||||
RID multimesh = mm->multimesh;
|
||||
mesh = storage->multimesh_get_mesh(multimesh);
|
||||
texture = mm->texture;
|
||||
|
||||
RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh);
|
||||
if (mesh_data) {
|
||||
for (int j = 0; j < mesh_data->surfaces.size(); j++) {
|
||||
RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
|
||||
// materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
|
||||
glBindVertexArray(s->array_id);
|
||||
|
||||
glVertexAttrib4f(RS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a);
|
||||
|
||||
if (s->index_array_len) {
|
||||
glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
|
||||
} else {
|
||||
glDrawArrays(gl_primitive[s->primitive], 0, s->array_len);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
|
||||
break;
|
||||
}
|
||||
|
||||
instance_count = storage->multimesh_get_instances_to_draw(multimesh);
|
||||
|
||||
RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
|
||||
push_constant.flags |= 1; //multimesh, trails disabled
|
||||
if (storage->multimesh_uses_colors(multimesh)) {
|
||||
push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
|
||||
}
|
||||
if (storage->multimesh_uses_custom_data(multimesh)) {
|
||||
push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
|
||||
}
|
||||
} else if (c->type == Item::Command::TYPE_PARTICLES) {
|
||||
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
|
||||
ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D);
|
||||
if (storage->particles_is_inactive(pt->particles)) {
|
||||
break;
|
||||
}
|
||||
int dpc = storage->particles_get_draw_passes(pt->particles);
|
||||
if (dpc == 0) {
|
||||
break; //nothing to draw
|
||||
}
|
||||
uint32_t divisor = 1;
|
||||
instance_count = storage->particles_get_amount(pt->particles, divisor);
|
||||
|
||||
RID uniform_set = storage->particles_get_instance_buffer_uniform_set(pt->particles, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
|
||||
|
||||
push_constant.flags |= divisor;
|
||||
instance_count /= divisor;
|
||||
|
||||
push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
|
||||
push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
|
||||
|
||||
mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored
|
||||
texture = pt->texture;
|
||||
}
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform);
|
||||
|
||||
} break;
|
||||
case Item::Command::TYPE_MULTIMESH: {
|
||||
Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c);
|
||||
|
||||
RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh);
|
||||
|
||||
if (!multi_mesh)
|
||||
if (mesh.is_null()) {
|
||||
break;
|
||||
|
||||
RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh);
|
||||
|
||||
if (!mesh_data)
|
||||
break;
|
||||
|
||||
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map);
|
||||
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
|
||||
//reset shader and force rebind
|
||||
state.using_texture_rect = true;
|
||||
_set_texture_rect_mode(false);
|
||||
|
||||
if (texture) {
|
||||
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
||||
}
|
||||
|
||||
int amount = MIN(multi_mesh->size, multi_mesh->visible_instances);
|
||||
_bind_canvas_texture(p_draw_list, texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
|
||||
|
||||
if (amount == -1) {
|
||||
amount = multi_mesh->size;
|
||||
uint32_t surf_count = storage->mesh_get_surface_count(mesh);
|
||||
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
|
||||
|
||||
push_constant.modulation[0] = base_color.r * modulate.r;
|
||||
push_constant.modulation[1] = base_color.g * modulate.g;
|
||||
push_constant.modulation[2] = base_color.b * modulate.b;
|
||||
push_constant.modulation[3] = base_color.a * modulate.a;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
push_constant.src_rect[j] = 0;
|
||||
push_constant.dst_rect[j] = 0;
|
||||
push_constant.ninepatch_margins[j] = 0;
|
||||
}
|
||||
|
||||
for (int j = 0; j < mesh_data->surfaces.size(); j++) {
|
||||
RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
|
||||
// materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
|
||||
glBindVertexArray(s->instancing_array_id);
|
||||
for (uint32_t j = 0; j < surf_count; j++) {
|
||||
void *surface = storage->mesh_get_surface(mesh, j);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
|
||||
RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface);
|
||||
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
|
||||
|
||||
int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4;
|
||||
glEnableVertexAttribArray(8);
|
||||
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9);
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4));
|
||||
glVertexAttribDivisor(9, 1);
|
||||
uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
|
||||
|
||||
int color_ofs;
|
||||
RID vertex_array;
|
||||
RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
|
||||
|
||||
if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) {
|
||||
glEnableVertexAttribArray(10);
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4));
|
||||
glVertexAttribDivisor(10, 1);
|
||||
color_ofs = 12 * 4;
|
||||
if (mesh_instance.is_valid()) {
|
||||
storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
|
||||
} else {
|
||||
glDisableVertexAttribArray(10);
|
||||
glVertexAttrib4f(10, 0, 0, 1, 0);
|
||||
color_ofs = 8 * 4;
|
||||
storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
|
||||
}
|
||||
|
||||
int custom_data_ofs = color_ofs;
|
||||
RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
|
||||
|
||||
switch (multi_mesh->color_format) {
|
||||
case RS::MULTIMESH_COLOR_NONE: {
|
||||
glDisableVertexAttribArray(11);
|
||||
glVertexAttrib4f(11, 1, 1, 1, 1);
|
||||
} break;
|
||||
case RS::MULTIMESH_COLOR_8BIT: {
|
||||
glEnableVertexAttribArray(11);
|
||||
glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
|
||||
glVertexAttribDivisor(11, 1);
|
||||
custom_data_ofs += 4;
|
||||
RID index_array = storage->mesh_surface_get_index_array(surface, 0);
|
||||
|
||||
} break;
|
||||
case RS::MULTIMESH_COLOR_FLOAT: {
|
||||
glEnableVertexAttribArray(11);
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
|
||||
glVertexAttribDivisor(11, 1);
|
||||
custom_data_ofs += 4 * 4;
|
||||
} break;
|
||||
if (index_array.is_valid()) {
|
||||
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, index_array);
|
||||
}
|
||||
|
||||
switch (multi_mesh->custom_data_format) {
|
||||
case RS::MULTIMESH_CUSTOM_DATA_NONE: {
|
||||
glDisableVertexAttribArray(12);
|
||||
glVertexAttrib4f(12, 1, 1, 1, 1);
|
||||
} break;
|
||||
case RS::MULTIMESH_CUSTOM_DATA_8BIT: {
|
||||
glEnableVertexAttribArray(12);
|
||||
glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
|
||||
glVertexAttribDivisor(12, 1);
|
||||
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, vertex_array);
|
||||
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
|
||||
|
||||
} break;
|
||||
case RS::MULTIMESH_CUSTOM_DATA_FLOAT: {
|
||||
glEnableVertexAttribArray(12);
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
|
||||
glVertexAttribDivisor(12, 1);
|
||||
} break;
|
||||
}
|
||||
|
||||
if (s->index_array_len) {
|
||||
glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
|
||||
} else {
|
||||
glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
RD::get_singleton()->draw_list_draw(p_draw_list, index_array.is_valid(), instance_count);
|
||||
}
|
||||
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
|
||||
state.using_texture_rect = true;
|
||||
_set_texture_rect_mode(false);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
push_constant.world[j] = world_backup[j];
|
||||
}
|
||||
|
||||
} break;
|
||||
case Item::Command::TYPE_PARTICLES: {
|
||||
Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c);
|
||||
|
||||
RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles);
|
||||
if (!particles)
|
||||
break;
|
||||
|
||||
if (particles->inactive && !particles->emitting)
|
||||
break;
|
||||
|
||||
glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
|
||||
|
||||
RenderingServerDefault::redraw_request();
|
||||
|
||||
storage->particles_request_process(particles_cmd->particles);
|
||||
//enable instancing
|
||||
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
|
||||
//reset shader and force rebind
|
||||
state.using_texture_rect = true;
|
||||
_set_texture_rect_mode(false);
|
||||
|
||||
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
|
||||
|
||||
if (texture) {
|
||||
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
||||
} else {
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0));
|
||||
}
|
||||
|
||||
if (!particles->use_local_coords) {
|
||||
Transform2D inv_xf;
|
||||
inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y));
|
||||
inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y));
|
||||
inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y));
|
||||
inv_xf.affine_invert();
|
||||
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
|
||||
}
|
||||
|
||||
glBindVertexArray(data.particle_quad_array); //use particle quad array
|
||||
glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
|
||||
|
||||
int stride = sizeof(float) * 4 * 6;
|
||||
|
||||
int amount = particles->amount;
|
||||
|
||||
if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) {
|
||||
glEnableVertexAttribArray(8); //xform x
|
||||
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9); //xform y
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
|
||||
glVertexAttribDivisor(9, 1);
|
||||
glEnableVertexAttribArray(10); //xform z
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
|
||||
glVertexAttribDivisor(10, 1);
|
||||
glEnableVertexAttribArray(11); //color
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
|
||||
glVertexAttribDivisor(11, 1);
|
||||
glEnableVertexAttribArray(12); //custom
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
|
||||
glVertexAttribDivisor(12, 1);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount);
|
||||
} else {
|
||||
//split
|
||||
int split = int(Math::ceil(particles->phase * particles->amount));
|
||||
|
||||
if (amount - split > 0) {
|
||||
glEnableVertexAttribArray(8); //xform x
|
||||
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3));
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9); //xform y
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4));
|
||||
glVertexAttribDivisor(9, 1);
|
||||
glEnableVertexAttribArray(10); //xform z
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5));
|
||||
glVertexAttribDivisor(10, 1);
|
||||
glEnableVertexAttribArray(11); //color
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0));
|
||||
glVertexAttribDivisor(11, 1);
|
||||
glEnableVertexAttribArray(12); //custom
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2));
|
||||
glVertexAttribDivisor(12, 1);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split);
|
||||
}
|
||||
|
||||
if (split > 0) {
|
||||
glEnableVertexAttribArray(8); //xform x
|
||||
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9); //xform y
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
|
||||
glVertexAttribDivisor(9, 1);
|
||||
glEnableVertexAttribArray(10); //xform z
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
|
||||
glVertexAttribDivisor(10, 1);
|
||||
glEnableVertexAttribArray(11); //color
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
|
||||
glVertexAttribDivisor(11, 1);
|
||||
glEnableVertexAttribArray(12); //custom
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
|
||||
glVertexAttribDivisor(12, 1);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split);
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
|
||||
state.using_texture_rect = true;
|
||||
_set_texture_rect_mode(false);
|
||||
|
||||
} break;
|
||||
#endif
|
||||
case Item::Command::TYPE_TRANSFORM: {
|
||||
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
|
||||
_update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world);
|
||||
|
@ -1437,6 +1279,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
|
||||
Item *canvas_group_owner = nullptr;
|
||||
|
||||
bool update_skeletons = false;
|
||||
|
||||
while (ci) {
|
||||
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
|
||||
backbuffer_copy = true;
|
||||
|
@ -1472,9 +1316,27 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
}
|
||||
}
|
||||
|
||||
if (ci->skeleton.is_valid()) {
|
||||
const Item::Command *c = ci->commands;
|
||||
|
||||
while (c) {
|
||||
if (c->type == Item::Command::TYPE_MESH) {
|
||||
const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
|
||||
if (cm->mesh_instance.is_valid()) {
|
||||
storage->mesh_instance_check_for_update(cm->mesh_instance);
|
||||
update_skeletons = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ci->canvas_group_owner != nullptr) {
|
||||
if (canvas_group_owner == nullptr) {
|
||||
//Canvas group begins here, render until before this item
|
||||
if (update_skeletons) {
|
||||
storage->update_mesh_instances();
|
||||
update_skeletons = false;
|
||||
}
|
||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
|
||||
item_count = 0;
|
||||
|
||||
|
@ -1494,6 +1356,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
}
|
||||
|
||||
if (ci == canvas_group_owner) {
|
||||
if (update_skeletons) {
|
||||
storage->update_mesh_instances();
|
||||
update_skeletons = false;
|
||||
}
|
||||
|
||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
|
||||
item_count = 0;
|
||||
|
||||
|
@ -1506,6 +1373,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
|
||||
if (backbuffer_copy) {
|
||||
//render anything pending, including clearing if no items
|
||||
if (update_skeletons) {
|
||||
storage->update_mesh_instances();
|
||||
update_skeletons = false;
|
||||
}
|
||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
|
||||
item_count = 0;
|
||||
|
||||
|
@ -1518,6 +1389,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
items[item_count++] = ci;
|
||||
|
||||
if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
|
||||
if (update_skeletons) {
|
||||
storage->update_mesh_instances();
|
||||
update_skeletons = false;
|
||||
}
|
||||
|
||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
|
||||
//then reset
|
||||
item_count = 0;
|
||||
|
|
|
@ -67,12 +67,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|||
};
|
||||
|
||||
enum {
|
||||
FLAGS_INSTANCING_STRIDE_MASK = 0xF,
|
||||
FLAGS_INSTANCING_ENABLED = (1 << 4),
|
||||
FLAGS_INSTANCING_HAS_COLORS = (1 << 5),
|
||||
FLAGS_INSTANCING_COLOR_8BIT = (1 << 6),
|
||||
FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 7),
|
||||
FLAGS_INSTANCING_CUSTOM_DATA_8_BIT = (1 << 8),
|
||||
|
||||
FLAGS_INSTANCING_MASK = 0x7F,
|
||||
FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
|
||||
FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
|
||||
|
||||
FLAGS_CLIP_RECT_UV = (1 << 9),
|
||||
FLAGS_TRANSPOSE_RECT = (1 << 10),
|
||||
|
|
|
@ -3873,6 +3873,18 @@ void RendererStorageRD::particles_initialize(RID p_rid) {
|
|||
particles_owner.initialize_rid(p_rid, Particles());
|
||||
}
|
||||
|
||||
void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND(!particles);
|
||||
if (particles->mode == p_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
_particles_free_data(particles);
|
||||
|
||||
particles->mode = p_mode;
|
||||
}
|
||||
|
||||
void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND(!particles);
|
||||
|
@ -4765,7 +4777,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
|
|||
copy_push_constant.total_particles *= copy_push_constant.total_particles;
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : ParticlesShader::COPY_MODE_FILL_INSTANCES]);
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : (particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES)]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
|
||||
if (do_sort) {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
|
||||
|
@ -4785,8 +4797,12 @@ void RendererStorageRD::_particles_update_buffers(Particles *particles) {
|
|||
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
|
||||
total_amount *= particles->trail_bind_poses.size();
|
||||
}
|
||||
|
||||
uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3;
|
||||
|
||||
particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * total_amount);
|
||||
particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * total_amount);
|
||||
|
||||
particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount);
|
||||
//needs to clear it
|
||||
|
||||
{
|
||||
|
@ -5004,7 +5020,7 @@ void RendererStorageRD::update_particles() {
|
|||
}
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES]);
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant));
|
||||
|
@ -9220,6 +9236,7 @@ RendererStorageRD::RendererStorageRD() {
|
|||
{
|
||||
Vector<String> copy_modes;
|
||||
copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n");
|
||||
copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define MODE_2D\n");
|
||||
copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n");
|
||||
copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n");
|
||||
|
||||
|
|
|
@ -580,6 +580,7 @@ private:
|
|||
|
||||
RID buffer; //storage buffer
|
||||
RID uniform_set_3d;
|
||||
RID uniform_set_2d;
|
||||
|
||||
bool dirty = false;
|
||||
MultiMesh *dirty_list = nullptr;
|
||||
|
@ -696,6 +697,7 @@ private:
|
|||
};
|
||||
|
||||
struct Particles {
|
||||
RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
|
||||
bool inactive = true;
|
||||
float inactive_time = 0.0;
|
||||
bool emitting = false;
|
||||
|
@ -822,6 +824,7 @@ private:
|
|||
|
||||
enum {
|
||||
COPY_MODE_FILL_INSTANCES,
|
||||
COPY_MODE_FILL_INSTANCES_2D,
|
||||
COPY_MODE_FILL_SORT_BUFFER,
|
||||
COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER,
|
||||
COPY_MODE_MAX,
|
||||
|
@ -1699,6 +1702,21 @@ public:
|
|||
return multimesh->uniform_set_3d;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
|
||||
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
|
||||
if (!multimesh->uniform_set_2d.is_valid()) {
|
||||
Vector<RD::Uniform> uniforms;
|
||||
RD::Uniform u;
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
u.binding = 0;
|
||||
u.ids.push_back(multimesh->buffer);
|
||||
uniforms.push_back(u);
|
||||
multimesh->uniform_set_2d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
|
||||
}
|
||||
|
||||
return multimesh->uniform_set_2d;
|
||||
}
|
||||
|
||||
/* IMMEDIATE API */
|
||||
|
||||
RID immediate_allocate() { return RID(); }
|
||||
|
@ -2093,6 +2111,7 @@ public:
|
|||
RID particles_allocate();
|
||||
void particles_initialize(RID p_particles_collision);
|
||||
|
||||
void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode);
|
||||
void particles_set_emitting(RID p_particles, bool p_emitting);
|
||||
void particles_set_amount(RID p_particles, int p_amount);
|
||||
void particles_set_lifetime(RID p_particles, float p_lifetime);
|
||||
|
@ -2137,6 +2156,12 @@ public:
|
|||
|
||||
virtual bool particles_is_inactive(RID p_particles) const;
|
||||
|
||||
_FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
|
||||
return particles->mode;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND_V(!particles, 0);
|
||||
|
|
|
@ -84,41 +84,85 @@ void main() {
|
|||
|
||||
mat4 world_matrix = mat4(vec4(draw_data.world_x, 0.0, 0.0), vec4(draw_data.world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data.world_ofs, 0.0, 1.0));
|
||||
|
||||
#if 0
|
||||
if (draw_data.flags & FLAGS_INSTANCING_ENABLED) {
|
||||
uint offset = draw_data.flags & FLAGS_INSTANCING_STRIDE_MASK;
|
||||
offset *= gl_InstanceIndex;
|
||||
mat4 instance_xform = mat4(
|
||||
vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), 0.0, texelFetch(instancing_buffer, offset + 3)),
|
||||
vec4(texelFetch(instancing_buffer, offset + 4), texelFetch(instancing_buffer, offset + 5), 0.0, texelFetch(instancing_buffer, offset + 7)),
|
||||
vec4(0.0, 0.0, 1.0, 0.0),
|
||||
vec4(0.0, 0.0, 0.0, 1.0));
|
||||
offset += 8;
|
||||
if (draw_data.flags & FLAGS_INSTANCING_HAS_COLORS) {
|
||||
vec4 instance_color;
|
||||
if (draw_data.flags & FLAGS_INSTANCING_COLOR_8_BIT) {
|
||||
uint bits = floatBitsToUint(texelFetch(instancing_buffer, offset));
|
||||
instance_color = unpackUnorm4x8(bits);
|
||||
offset += 1;
|
||||
} else {
|
||||
instance_color = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3));
|
||||
offset += 4;
|
||||
}
|
||||
#define FLAGS_INSTANCING_MASK 0x7F
|
||||
#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
|
||||
#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
|
||||
|
||||
color *= instance_color;
|
||||
uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
|
||||
|
||||
#ifdef USE_ATTRIBUTES
|
||||
|
||||
if (instancing > 1) {
|
||||
// trails
|
||||
|
||||
uint stride = 2 + 1 + 1; //particles always uses this format
|
||||
|
||||
uint trail_size = instancing;
|
||||
|
||||
uint offset = trail_size * stride * gl_InstanceIndex;
|
||||
|
||||
mat4 matrix;
|
||||
vec4 pcolor;
|
||||
{
|
||||
uint boffset = offset + bone_attrib.x * stride;
|
||||
matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
|
||||
pcolor = transforms.data[boffset + 3] * weight_attrib.x;
|
||||
}
|
||||
if (draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA) {
|
||||
if (draw_data.flags & FLAGS_INSTANCING_CUSTOM_DATA_8_BIT) {
|
||||
uint bits = floatBitsToUint(texelFetch(instancing_buffer, offset));
|
||||
instance_custom = unpackUnorm4x8(bits);
|
||||
} else {
|
||||
instance_custom = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3));
|
||||
if (weight_attrib.y > 0.001) {
|
||||
uint boffset = offset + bone_attrib.y * stride;
|
||||
matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
|
||||
pcolor += transforms.data[boffset + 3] * weight_attrib.y;
|
||||
}
|
||||
if (weight_attrib.z > 0.001) {
|
||||
uint boffset = offset + bone_attrib.z * stride;
|
||||
matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
|
||||
pcolor += transforms.data[boffset + 3] * weight_attrib.z;
|
||||
}
|
||||
if (weight_attrib.w > 0.001) {
|
||||
uint boffset = offset + bone_attrib.w * stride;
|
||||
matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
|
||||
pcolor += transforms.data[boffset + 3] * weight_attrib.w;
|
||||
}
|
||||
|
||||
instance_custom = transforms.data[offset + 4];
|
||||
|
||||
color *= pcolor;
|
||||
|
||||
matrix = transpose(matrix);
|
||||
world_matrix = world_matrix * matrix;
|
||||
|
||||
} else
|
||||
#endif // USE_ATTRIBUTES
|
||||
|
||||
if (instancing == 1) {
|
||||
uint stride = 2;
|
||||
{
|
||||
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
|
||||
stride += 1;
|
||||
}
|
||||
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
|
||||
stride += 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint offset = stride * gl_InstanceIndex;
|
||||
|
||||
mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
|
||||
offset += 2;
|
||||
|
||||
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
|
||||
color *= transforms.data[offset];
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
|
||||
instance_custom = transforms.data[offset];
|
||||
}
|
||||
|
||||
matrix = transpose(matrix);
|
||||
world_matrix = world_matrix * matrix;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
|
||||
if (bool(draw_data.flags & FLAGS_USING_PARTICLES)) {
|
||||
//scale by texture size
|
||||
|
|
|
@ -5,12 +5,10 @@
|
|||
|
||||
#define SDF_MAX_LENGTH 16384.0
|
||||
|
||||
#define FLAGS_INSTANCING_STRIDE_MASK 0xF
|
||||
#define FLAGS_INSTANCING_ENABLED (1 << 4)
|
||||
#define FLAGS_INSTANCING_HAS_COLORS (1 << 5)
|
||||
#define FLAGS_INSTANCING_COLOR_8BIT (1 << 6)
|
||||
#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 7)
|
||||
#define FLAGS_INSTANCING_CUSTOM_DATA_8_BIT (1 << 8)
|
||||
//1 means enabled, 2+ means trails in use
|
||||
#define FLAGS_INSTANCING_MASK 0x7F
|
||||
#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
|
||||
#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
|
||||
|
||||
#define FLAGS_CLIP_RECT_UV (1 << 9)
|
||||
#define FLAGS_TRANSPOSE_RECT (1 << 10)
|
||||
|
|
|
@ -163,11 +163,20 @@ void main() {
|
|||
txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible
|
||||
}
|
||||
|
||||
#ifdef MODE_2D
|
||||
|
||||
instances.data[write_offset + 0] = txform[0];
|
||||
instances.data[write_offset + 1] = txform[1];
|
||||
instances.data[write_offset + 2] = particles.data[particle].color;
|
||||
instances.data[write_offset + 3] = particles.data[particle].custom;
|
||||
|
||||
#else
|
||||
instances.data[write_offset + 0] = txform[0];
|
||||
instances.data[write_offset + 1] = txform[1];
|
||||
instances.data[write_offset + 2] = txform[2];
|
||||
instances.data[write_offset + 3] = particles.data[particle].color;
|
||||
instances.data[write_offset + 4] = particles.data[particle].custom;
|
||||
#endif //MODE_2D
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -74,6 +74,53 @@ void main() {
|
|||
|
||||
#ifdef MODE_2D
|
||||
vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1]));
|
||||
|
||||
if (params.has_blend_shape) {
|
||||
float blend_total = 0.0;
|
||||
vec2 blend_vertex = vec2(0.0);
|
||||
|
||||
for (uint i = 0; i < params.blend_shape_count; i++) {
|
||||
float w = blend_shape_weights.data[i];
|
||||
if (abs(w) > 0.0001) {
|
||||
uint base_offset = (params.vertex_count * i + index) * params.vertex_stride;
|
||||
|
||||
blend_vertex += uintBitsToFloat(uvec2(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1])) * w;
|
||||
|
||||
base_offset += 2;
|
||||
|
||||
blend_total += w;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.normalized_blend_shapes) {
|
||||
vertex = (1.0 - blend_total) * vertex;
|
||||
}
|
||||
|
||||
vertex += blend_vertex;
|
||||
}
|
||||
|
||||
if (params.has_skeleton) {
|
||||
uint skin_offset = params.skin_stride * index;
|
||||
|
||||
uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]);
|
||||
uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset
|
||||
uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3;
|
||||
|
||||
skin_offset += params.skin_weight_offset;
|
||||
|
||||
uvec2 weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]);
|
||||
|
||||
vec2 weights_01 = unpackUnorm2x16(weights.x);
|
||||
vec2 weights_23 = unpackUnorm2x16(weights.y);
|
||||
|
||||
mat4 m = mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x;
|
||||
m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y;
|
||||
m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x;
|
||||
m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y;
|
||||
|
||||
//reverse order because its transposed
|
||||
vertex = (vec4(vertex, 0.0, 1.0) * m).xy;
|
||||
}
|
||||
#else
|
||||
vec3 vertex;
|
||||
vec3 normal;
|
||||
|
|
|
@ -484,6 +484,7 @@ public:
|
|||
|
||||
virtual RID particles_allocate() = 0;
|
||||
virtual void particles_initialize(RID p_rid) = 0;
|
||||
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) = 0;
|
||||
|
||||
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
|
||||
virtual bool particles_get_emitting(RID p_particles) = 0;
|
||||
|
|
|
@ -478,6 +478,7 @@ public:
|
|||
|
||||
FUNCRIDSPLIT(particles)
|
||||
|
||||
FUNC2(particles_set_mode, RID, ParticlesMode)
|
||||
FUNC2(particles_set_emitting, RID, bool)
|
||||
FUNC1R(bool, particles_get_emitting, RID)
|
||||
FUNC2(particles_set_amount, RID, int)
|
||||
|
|
|
@ -858,8 +858,10 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
|
|||
case Variant::PACKED_VECTOR2_ARRAY: {
|
||||
Vector<Vector2> v2 = p_arrays[i];
|
||||
array_len = v2.size();
|
||||
format |= ARRAY_FLAG_USE_2D_VERTICES;
|
||||
} break;
|
||||
case Variant::PACKED_VECTOR3_ARRAY: {
|
||||
ERR_FAIL_COND_V(p_compress_format & ARRAY_FLAG_USE_2D_VERTICES, ERR_INVALID_PARAMETER);
|
||||
Vector<Vector3> v3 = p_arrays[i];
|
||||
array_len = v3.size();
|
||||
} break;
|
||||
|
|
|
@ -618,6 +618,12 @@ public:
|
|||
|
||||
virtual RID particles_create() = 0;
|
||||
|
||||
enum ParticlesMode {
|
||||
PARTICLES_MODE_2D,
|
||||
PARTICLES_MODE_3D
|
||||
};
|
||||
virtual void particles_set_mode(RID p_particles, ParticlesMode p_mode) = 0;
|
||||
|
||||
virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0;
|
||||
virtual bool particles_get_emitting(RID p_particles) = 0;
|
||||
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
|
||||
|
|
Loading…
Reference in New Issue