2D GPU Particles working..
This commit is contained in:
parent
3c1fd26bb0
commit
95560e02c5
|
@ -28,6 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "rasterizer_canvas_gles3.h"
|
||||
#include "servers/visual/visual_server_raster.h"
|
||||
|
||||
#include "global_config.h"
|
||||
#include "os/os.h"
|
||||
|
@ -607,6 +608,133 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
|
|||
}
|
||||
_draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1);
|
||||
|
||||
} 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;
|
||||
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
|
||||
|
||||
VisualServerRaster::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 / particles_cmd->h_frames), 1.0 / (texture->height / particles_cmd->v_frames));
|
||||
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);
|
||||
}
|
||||
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::H_FRAMES, particles_cmd->h_frames);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::V_FRAMES, particles_cmd->v_frames);
|
||||
|
||||
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 != VS::PARTICLES_DRAW_ORDER_LIFETIME) {
|
||||
|
||||
glEnableVertexAttribArray(8); //xform x
|
||||
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3);
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9); //xform y
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4);
|
||||
glVertexAttribDivisor(9, 1);
|
||||
glEnableVertexAttribArray(10); //xform z
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5);
|
||||
glVertexAttribDivisor(10, 1);
|
||||
glEnableVertexAttribArray(11); //color
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0);
|
||||
glVertexAttribDivisor(11, 1);
|
||||
glEnableVertexAttribArray(12); //custom
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2);
|
||||
glVertexAttribDivisor(12, 1);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount);
|
||||
} else {
|
||||
//split
|
||||
|
||||
int stride = sizeof(float) * 4 * 6;
|
||||
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, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 3);
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9); //xform y
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 4);
|
||||
glVertexAttribDivisor(9, 1);
|
||||
glEnableVertexAttribArray(10); //xform z
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 5);
|
||||
glVertexAttribDivisor(10, 1);
|
||||
glEnableVertexAttribArray(11); //color
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + 0);
|
||||
glVertexAttribDivisor(11, 1);
|
||||
glEnableVertexAttribArray(12); //custom
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 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, ((uint8_t *)NULL) + sizeof(float) * 4 * 3);
|
||||
glVertexAttribDivisor(8, 1);
|
||||
glEnableVertexAttribArray(9); //xform y
|
||||
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4);
|
||||
glVertexAttribDivisor(9, 1);
|
||||
glEnableVertexAttribArray(10); //xform z
|
||||
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5);
|
||||
glVertexAttribDivisor(10, 1);
|
||||
glEnableVertexAttribArray(11); //color
|
||||
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0);
|
||||
glVertexAttribDivisor(11, 1);
|
||||
glEnableVertexAttribArray(12); //custom
|
||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 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_INSTANCING, false);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
|
||||
state.using_texture_rect = true;
|
||||
_set_texture_rect_mode(false);
|
||||
|
||||
} break;
|
||||
case Item::Command::TYPE_CIRCLE: {
|
||||
|
||||
|
@ -1351,7 +1479,39 @@ void RasterizerCanvasGLES3::initialize() {
|
|||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
|
||||
}
|
||||
{
|
||||
//particle quad buffers
|
||||
|
||||
glGenBuffers(1, &data.particle_quad_vertices);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices);
|
||||
{
|
||||
//quad of size 1, with pivot on the center for particles, then regular UVS. Color is general plus fetched from particle
|
||||
const float qv[16] = {
|
||||
-0.5, -0.5,
|
||||
0.0, 0.0,
|
||||
-0.5, 0.5,
|
||||
0.0, 1.0,
|
||||
0.5, 0.5,
|
||||
1.0, 1.0,
|
||||
0.5, -0.5,
|
||||
1.0, 0.0
|
||||
};
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
|
||||
|
||||
glGenVertexArrays(1, &data.particle_quad_array);
|
||||
glBindVertexArray(data.particle_quad_array);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices);
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (float *)0 + 2);
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
|
||||
}
|
||||
{
|
||||
|
||||
uint32_t poly_size = GLOBAL_DEF("rendering/buffers/canvas_polygon_buffer_size_kb", 128);
|
||||
|
@ -1428,6 +1588,9 @@ void RasterizerCanvasGLES3::finalize() {
|
|||
glDeleteBuffers(1, &data.canvas_quad_vertices);
|
||||
glDeleteVertexArrays(1, &data.canvas_quad_array);
|
||||
|
||||
glDeleteBuffers(1, &data.canvas_quad_vertices);
|
||||
glDeleteVertexArrays(1, &data.canvas_quad_array);
|
||||
|
||||
glDeleteVertexArrays(1, &data.polygon_buffer_pointer_array);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ public:
|
|||
GLuint polygon_buffer_quad_arrays[4];
|
||||
GLuint polygon_buffer_pointer_array;
|
||||
GLuint polygon_index_buffer;
|
||||
|
||||
GLuint particle_quad_vertices;
|
||||
GLuint particle_quad_array;
|
||||
|
||||
uint32_t polygon_buffer_size;
|
||||
|
||||
} data;
|
||||
|
|
|
@ -2326,6 +2326,9 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
|
|||
if (E->get().order < 0)
|
||||
continue; // texture, does not go here
|
||||
|
||||
//if (material->shader->mode == VS::SHADER_PARTICLES) {
|
||||
// print_line("uniform " + String(E->key()) + " order " + itos(E->get().order) + " offset " + itos(material->shader->ubo_offsets[E->get().order]));
|
||||
//}
|
||||
//regular uniform
|
||||
uint8_t *data = &local_ubo[material->shader->ubo_offsets[E->get().order]];
|
||||
|
||||
|
|
|
@ -361,6 +361,8 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
|
|||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
//_display_error_with_code("pepo", strings);
|
||||
|
||||
/* FRAGMENT SHADER */
|
||||
|
||||
strings.resize(strings_base_size);
|
||||
|
|
|
@ -11,11 +11,26 @@ uniform vec4 src_rect;
|
|||
|
||||
#else
|
||||
|
||||
#ifdef USE_INSTANCING
|
||||
|
||||
layout(location=8) in highp vec4 instance_xform0;
|
||||
layout(location=9) in highp vec4 instance_xform1;
|
||||
layout(location=10) in highp vec4 instance_xform2;
|
||||
layout(location=11) in lowp vec4 instance_color;
|
||||
|
||||
#ifdef USE_INSTANCE_CUSTOM
|
||||
layout(location=12) in highp vec4 instance_custom_data;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
layout(location=4) in highp vec2 uv_attrib;
|
||||
|
||||
//skeletn
|
||||
#endif
|
||||
|
||||
uniform highp vec2 color_texpixel_size;
|
||||
|
||||
|
||||
layout(std140) uniform CanvasItemData { //ubo:0
|
||||
|
||||
|
@ -64,7 +79,10 @@ const bool at_light_pass = true;
|
|||
const bool at_light_pass = false;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_PARTICLES
|
||||
uniform int h_frames;
|
||||
uniform int v_frames;
|
||||
#endif
|
||||
|
||||
VERTEX_SHADER_GLOBALS
|
||||
|
||||
|
@ -82,6 +100,12 @@ void main() {
|
|||
|
||||
vec4 vertex_color = color_attrib;
|
||||
|
||||
#ifdef USE_INSTANCING
|
||||
mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0)));
|
||||
vertex_color*=instance_color;
|
||||
#else
|
||||
mat4 extra_matrix2 = extra_matrix;
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXTURE_RECT
|
||||
|
||||
|
@ -95,6 +119,22 @@ void main() {
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef USE_PARTICLES
|
||||
//scale by texture size
|
||||
outvec.xy/=color_texpixel_size;
|
||||
|
||||
//compute h and v frames and adjust UV interp for animation
|
||||
int total_frames = h_frames * v_frames;
|
||||
int frame = min(int(float(total_frames) *instance_custom_data.z),total_frames-1);
|
||||
float frame_w = 1.0/float(h_frames);
|
||||
float frame_h = 1.0/float(v_frames);
|
||||
uv_interp.x = uv_interp.x * frame_w + frame_w * float(frame % h_frames);
|
||||
uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / v_frames);
|
||||
|
||||
#endif
|
||||
|
||||
#define extra_matrix extra_matrix2
|
||||
|
||||
{
|
||||
vec2 src_vtx=outvec.xy;
|
||||
|
||||
|
@ -107,6 +147,8 @@ VERTEX_SHADER_CODE
|
|||
outvec = modelview_matrix * outvec;
|
||||
#endif
|
||||
|
||||
#undef extra_matrix
|
||||
|
||||
color_interp = vertex_color;
|
||||
|
||||
#ifdef USE_PIXEL_SNAP
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 443 B |
|
@ -31,8 +31,8 @@
|
|||
|
||||
#include "canvas_item_editor_plugin.h"
|
||||
#include "io/image_loader.h"
|
||||
#include "scene/3d/particles.h"
|
||||
#include "scene/gui/separator.h"
|
||||
|
||||
void Particles2DEditorPlugin::edit(Object *p_object) {
|
||||
|
||||
if (p_object) {
|
||||
|
@ -62,65 +62,16 @@ void Particles2DEditorPlugin::_file_selected(const String &p_file) {
|
|||
|
||||
print_line("file: " + p_file);
|
||||
|
||||
int epc = epoints->get_value();
|
||||
|
||||
Ref<Image> img;
|
||||
img.instance();
|
||||
Error err = ImageLoader::load_image(p_file, img);
|
||||
ERR_EXPLAIN(TTR("Error loading image:") + " " + p_file);
|
||||
ERR_FAIL_COND(err != OK);
|
||||
|
||||
img->convert(Image::FORMAT_LA8);
|
||||
ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8);
|
||||
Size2i s = Size2(img->get_width(), img->get_height());
|
||||
ERR_FAIL_COND(s.width == 0 || s.height == 0);
|
||||
|
||||
PoolVector<uint8_t> data = img->get_data();
|
||||
PoolVector<uint8_t>::Read r = data.read();
|
||||
|
||||
Vector<Point2i> valid_positions;
|
||||
valid_positions.resize(s.width * s.height);
|
||||
int vpc = 0;
|
||||
|
||||
for (int i = 0; i < s.width * s.height; i++) {
|
||||
|
||||
uint8_t a = r[i * 2 + 1];
|
||||
if (a > 128) {
|
||||
valid_positions[vpc++] = Point2i(i % s.width, i / s.width);
|
||||
}
|
||||
}
|
||||
|
||||
valid_positions.resize(vpc);
|
||||
|
||||
ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image.."));
|
||||
ERR_FAIL_COND(valid_positions.size() == 0);
|
||||
|
||||
PoolVector<Point2> epoints;
|
||||
epoints.resize(epc);
|
||||
PoolVector<Point2>::Write w = epoints.write();
|
||||
|
||||
Size2 extents = Size2(img->get_width() * 0.5, img->get_height() * 0.5);
|
||||
|
||||
for (int i = 0; i < epc; i++) {
|
||||
|
||||
Point2 p = valid_positions[Math::rand() % vpc];
|
||||
p -= s / 2;
|
||||
w[i] = p / extents;
|
||||
}
|
||||
|
||||
w = PoolVector<Point2>::Write();
|
||||
|
||||
undo_redo->create_action(TTR("Set Emission Mask"));
|
||||
undo_redo->add_do_method(particles, "set_emission_points", epoints);
|
||||
undo_redo->add_do_method(particles, "set_emission_half_extents", extents);
|
||||
undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points());
|
||||
undo_redo->add_undo_method(particles, "set_emission_half_extents", particles->get_emission_half_extents());
|
||||
undo_redo->commit_action();
|
||||
source_emission_file = p_file;
|
||||
emission_mask->popup_centered_minsize();
|
||||
}
|
||||
|
||||
void Particles2DEditorPlugin::_menu_callback(int p_idx) {
|
||||
|
||||
switch (p_idx) {
|
||||
case MENU_GENERATE_VISIBILITY_RECT: {
|
||||
generate_aabb->popup_centered_minsize();
|
||||
} break;
|
||||
case MENU_LOAD_EMISSION_MASK: {
|
||||
|
||||
file->popup_centered_ratio();
|
||||
|
@ -128,14 +79,249 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) {
|
|||
} break;
|
||||
case MENU_CLEAR_EMISSION_MASK: {
|
||||
|
||||
undo_redo->create_action(TTR("Clear Emission Mask"));
|
||||
emission_mask->popup_centered_minsize();
|
||||
|
||||
/*undo_redo->create_action(TTR("Clear Emission Mask"));
|
||||
undo_redo->add_do_method(particles, "set_emission_points", PoolVector<Vector2>());
|
||||
undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points());
|
||||
undo_redo->commit_action();
|
||||
undo_redo->commit_action();*/
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void Particles2DEditorPlugin::_generate_visibility_rect() {
|
||||
|
||||
float time = generate_seconds->get_value();
|
||||
|
||||
float running = 0.0;
|
||||
|
||||
EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
|
||||
|
||||
Rect2 rect;
|
||||
while (running < time) {
|
||||
|
||||
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
|
||||
ep.step("Generating..", int(running), true);
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
|
||||
Rect2 capture = particles->capture_rect();
|
||||
if (rect == Rect2())
|
||||
rect = capture;
|
||||
else
|
||||
rect = rect.merge(capture);
|
||||
|
||||
running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
|
||||
}
|
||||
|
||||
particles->set_visibility_rect(rect);
|
||||
}
|
||||
|
||||
void Particles2DEditorPlugin::_generate_emission_mask() {
|
||||
|
||||
Ref<ParticlesMaterial> pm = particles->get_process_material();
|
||||
if (!pm.is_valid()) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material"));
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Image> img;
|
||||
img.instance();
|
||||
Error err = ImageLoader::load_image(source_emission_file, img);
|
||||
ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file);
|
||||
ERR_FAIL_COND(err != OK);
|
||||
|
||||
if (img->is_compressed()) {
|
||||
img->decompress();
|
||||
}
|
||||
img->convert(Image::FORMAT_RGBA8);
|
||||
ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
|
||||
Size2i s = Size2(img->get_width(), img->get_height());
|
||||
ERR_FAIL_COND(s.width == 0 || s.height == 0);
|
||||
|
||||
Vector<Point2> valid_positions;
|
||||
Vector<Point2> valid_normals;
|
||||
Vector<uint8_t> valid_colors;
|
||||
|
||||
valid_positions.resize(s.width * s.height);
|
||||
|
||||
EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected();
|
||||
|
||||
if (emode == EMISSION_MODE_BORDER_DIRECTED) {
|
||||
valid_normals.resize(s.width * s.height);
|
||||
}
|
||||
|
||||
bool capture_colors = emission_colors->is_pressed();
|
||||
|
||||
if (capture_colors) {
|
||||
valid_colors.resize(s.width * s.height * 4);
|
||||
}
|
||||
|
||||
int vpc = 0;
|
||||
|
||||
{
|
||||
PoolVector<uint8_t> data = img->get_data();
|
||||
PoolVector<uint8_t>::Read r = data.read();
|
||||
|
||||
for (int i = 0; i < s.width; i++) {
|
||||
for (int j = 0; j < s.height; j++) {
|
||||
|
||||
uint8_t a = r[(j * s.width + i) * 4 + 3];
|
||||
|
||||
if (a > 128) {
|
||||
|
||||
if (emode == EMISSION_MODE_SOLID) {
|
||||
|
||||
if (capture_colors) {
|
||||
valid_colors[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
|
||||
valid_colors[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
|
||||
valid_colors[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
|
||||
valid_colors[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
|
||||
}
|
||||
valid_positions[vpc++] = Point2(i, j);
|
||||
|
||||
} else {
|
||||
|
||||
bool on_border = false;
|
||||
for (int x = i - 1; x <= i + 1; x++) {
|
||||
for (int y = j - 1; y <= j + 1; y++) {
|
||||
|
||||
if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
|
||||
on_border = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (on_border)
|
||||
break;
|
||||
}
|
||||
|
||||
if (on_border) {
|
||||
valid_positions[vpc] = Point2(i, j);
|
||||
|
||||
if (emode == EMISSION_MODE_BORDER_DIRECTED) {
|
||||
Vector2 normal;
|
||||
for (int x = i - 2; x <= i + 2; x++) {
|
||||
for (int y = j - 2; y <= j + 2; y++) {
|
||||
|
||||
if (x == i && y == j)
|
||||
continue;
|
||||
|
||||
if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
|
||||
normal += Vector2(x - i, y - j).normalized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
normal.normalize();
|
||||
valid_normals[vpc] = normal;
|
||||
}
|
||||
|
||||
if (capture_colors) {
|
||||
valid_colors[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
|
||||
valid_colors[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
|
||||
valid_colors[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
|
||||
valid_colors[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
|
||||
}
|
||||
|
||||
vpc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valid_positions.resize(vpc);
|
||||
if (valid_normals.size()) {
|
||||
valid_normals.resize(vpc);
|
||||
}
|
||||
|
||||
ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image.."));
|
||||
ERR_FAIL_COND(valid_positions.size() == 0);
|
||||
|
||||
PoolVector<uint8_t> texdata;
|
||||
|
||||
int w = 2048;
|
||||
int h = (vpc / 2048) + 1;
|
||||
|
||||
texdata.resize(w * h * 2 * sizeof(float));
|
||||
|
||||
{
|
||||
PoolVector<uint8_t>::Write tw = texdata.write();
|
||||
float *twf = (float *)tw.ptr();
|
||||
for (int i = 0; i < vpc; i++) {
|
||||
|
||||
twf[i * 2 + 0] = valid_positions[i].x;
|
||||
twf[i * 2 + 1] = valid_positions[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
img.instance();
|
||||
img->create(w, h, false, Image::FORMAT_RGF, texdata);
|
||||
|
||||
Ref<ImageTexture> imgt;
|
||||
imgt.instance();
|
||||
imgt->create_from_image(img, 0);
|
||||
|
||||
pm->set_emission_point_texture(imgt);
|
||||
pm->set_emission_point_count(vpc);
|
||||
|
||||
if (capture_colors) {
|
||||
|
||||
PoolVector<uint8_t> colordata;
|
||||
colordata.resize(w * h * 4); //use RG texture
|
||||
|
||||
{
|
||||
PoolVector<uint8_t>::Write tw = colordata.write();
|
||||
for (int i = 0; i < vpc * 4; i++) {
|
||||
|
||||
tw[i] = valid_colors[i];
|
||||
}
|
||||
}
|
||||
|
||||
img.instance();
|
||||
img->create(w, h, false, Image::FORMAT_RGBA8, colordata);
|
||||
|
||||
imgt.instance();
|
||||
imgt->create_from_image(img, 0);
|
||||
pm->set_emission_color_texture(imgt);
|
||||
}
|
||||
|
||||
if (valid_normals.size()) {
|
||||
pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
|
||||
|
||||
PoolVector<uint8_t> normdata;
|
||||
normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
|
||||
|
||||
{
|
||||
PoolVector<uint8_t>::Write tw = normdata.write();
|
||||
float *twf = (float *)tw.ptr();
|
||||
for (int i = 0; i < vpc; i++) {
|
||||
twf[i * 2 + 0] = valid_normals[i].x;
|
||||
twf[i * 2 + 1] = valid_normals[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
img.instance();
|
||||
img->create(w, h, false, Image::FORMAT_RGF, normdata);
|
||||
|
||||
imgt.instance();
|
||||
imgt->create_from_image(img, 0);
|
||||
pm->set_emission_normal_texture(imgt);
|
||||
|
||||
} else {
|
||||
pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
|
||||
}
|
||||
|
||||
/*undo_redo->create_action(TTR("Set Emission Mask"));
|
||||
undo_redo->add_do_method(particles, "set_emission_points", epoints);
|
||||
undo_redo->add_do_method(particles, "set_emission_half_extents", extents);
|
||||
undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points());
|
||||
undo_redo->add_undo_method(particles, "set_emission_half_extents", particles->get_emission_half_extents());
|
||||
undo_redo->commit_action();
|
||||
*/
|
||||
}
|
||||
|
||||
void Particles2DEditorPlugin::_notification(int p_what) {
|
||||
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
|
@ -150,6 +336,8 @@ void Particles2DEditorPlugin::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("_menu_callback"), &Particles2DEditorPlugin::_menu_callback);
|
||||
ClassDB::bind_method(D_METHOD("_file_selected"), &Particles2DEditorPlugin::_file_selected);
|
||||
ClassDB::bind_method(D_METHOD("_generate_visibility_rect"), &Particles2DEditorPlugin::_generate_visibility_rect);
|
||||
ClassDB::bind_method(D_METHOD("_generate_emission_mask"), &Particles2DEditorPlugin::_generate_emission_mask);
|
||||
}
|
||||
|
||||
Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
|
||||
|
@ -165,8 +353,10 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
|
|||
toolbar->add_child(memnew(VSeparator));
|
||||
|
||||
menu = memnew(MenuButton);
|
||||
menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT);
|
||||
menu->get_popup()->add_separator();
|
||||
menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
|
||||
menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
|
||||
// menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
|
||||
menu->set_text("Particles");
|
||||
toolbar->add_child(menu);
|
||||
|
||||
|
@ -185,6 +375,37 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
|
|||
epoints->set_step(1);
|
||||
epoints->set_value(512);
|
||||
file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints);
|
||||
|
||||
generate_aabb = memnew(ConfirmationDialog);
|
||||
generate_aabb->set_title(TTR("Generate Visibility Rect"));
|
||||
VBoxContainer *genvb = memnew(VBoxContainer);
|
||||
generate_aabb->add_child(genvb);
|
||||
generate_seconds = memnew(SpinBox);
|
||||
genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
|
||||
generate_seconds->set_min(0.1);
|
||||
generate_seconds->set_max(25);
|
||||
generate_seconds->set_value(2);
|
||||
|
||||
toolbar->add_child(generate_aabb);
|
||||
|
||||
generate_aabb->connect("confirmed", this, "_generate_visibility_rect");
|
||||
|
||||
emission_mask = memnew(ConfirmationDialog);
|
||||
emission_mask->set_title(TTR("Generate Visibility Rect"));
|
||||
VBoxContainer *emvb = memnew(VBoxContainer);
|
||||
emission_mask->add_child(emvb);
|
||||
emission_mask_mode = memnew(OptionButton);
|
||||
emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode);
|
||||
emission_mask_mode->add_item("Solid Pixels", EMISSION_MODE_SOLID);
|
||||
emission_mask_mode->add_item("Border Pixels", EMISSION_MODE_BORDER);
|
||||
emission_mask_mode->add_item("Directed Border Pixels", EMISSION_MODE_BORDER_DIRECTED);
|
||||
emission_colors = memnew(CheckBox);
|
||||
emission_colors->set_text(TTR("Capture from Pixel"));
|
||||
emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
|
||||
|
||||
toolbar->add_child(emission_mask);
|
||||
|
||||
emission_mask->connect("confirmed", this, "_generate_emission_mask");
|
||||
}
|
||||
|
||||
Particles2DEditorPlugin::~Particles2DEditorPlugin() {
|
||||
|
|
|
@ -44,10 +44,17 @@ class Particles2DEditorPlugin : public EditorPlugin {
|
|||
|
||||
enum {
|
||||
|
||||
MENU_GENERATE_VISIBILITY_RECT,
|
||||
MENU_LOAD_EMISSION_MASK,
|
||||
MENU_CLEAR_EMISSION_MASK
|
||||
};
|
||||
|
||||
enum EmissionMode {
|
||||
EMISSION_MODE_SOLID,
|
||||
EMISSION_MODE_BORDER,
|
||||
EMISSION_MODE_BORDER_DIRECTED
|
||||
};
|
||||
|
||||
Particles2D *particles;
|
||||
|
||||
EditorFileDialog *file;
|
||||
|
@ -58,9 +65,20 @@ class Particles2DEditorPlugin : public EditorPlugin {
|
|||
|
||||
SpinBox *epoints;
|
||||
|
||||
ConfirmationDialog *generate_aabb;
|
||||
SpinBox *generate_seconds;
|
||||
|
||||
ConfirmationDialog *emission_mask;
|
||||
OptionButton *emission_mask_mode;
|
||||
CheckBox *emission_colors;
|
||||
|
||||
String source_emission_file;
|
||||
|
||||
UndoRedo *undo_redo;
|
||||
void _file_selected(const String &p_file);
|
||||
void _menu_callback(int p_idx);
|
||||
void _generate_visibility_rect();
|
||||
void _generate_emission_mask();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
|
@ -417,14 +417,22 @@ void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color
|
|||
VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
|
||||
}
|
||||
|
||||
void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color) {
|
||||
void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) {
|
||||
|
||||
if (!drawing) {
|
||||
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
|
||||
if (p_filled) {
|
||||
|
||||
VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
|
||||
} else {
|
||||
VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(p_rect.size.width, 0), p_color);
|
||||
VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(0, p_rect.size.height), p_color);
|
||||
VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(0, p_rect.size.height), p_rect.position + p_rect.size, p_color);
|
||||
VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(p_rect.size.width, 0), p_rect.position + p_rect.size, p_color);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
|
||||
|
@ -754,7 +762,7 @@ void CanvasItem::_bind_methods() {
|
|||
//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color"), &CanvasItem::draw_rect);
|
||||
ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true));
|
||||
ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle);
|
||||
ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant()));
|
||||
ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()));
|
||||
|
|
|
@ -156,7 +156,7 @@ public:
|
|||
/* DRAWING API */
|
||||
|
||||
void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
|
||||
void draw_rect(const Rect2 &p_rect, const Color &p_color);
|
||||
void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true);
|
||||
void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
|
||||
void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>());
|
||||
void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>());
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,235 +34,98 @@
|
|||
#include "scene/resources/color_ramp.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
class Particles2D;
|
||||
class ParticleAttractor2D : public Node2D {
|
||||
|
||||
GDCLASS(ParticleAttractor2D, Node2D);
|
||||
|
||||
friend class Particles2D;
|
||||
bool enabled;
|
||||
float radius;
|
||||
float disable_radius;
|
||||
float gravity;
|
||||
float absorption;
|
||||
NodePath path;
|
||||
|
||||
Particles2D *owner;
|
||||
|
||||
void _update_owner();
|
||||
void _owner_exited();
|
||||
void _set_owner(Particles2D *p_owner);
|
||||
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_enabled(bool p_enabled);
|
||||
bool is_enabled() const;
|
||||
|
||||
void set_radius(float p_radius);
|
||||
float get_radius() const;
|
||||
|
||||
void set_disable_radius(float p_disable_radius);
|
||||
float get_disable_radius() const;
|
||||
|
||||
void set_gravity(float p_gravity);
|
||||
float get_gravity() const;
|
||||
|
||||
void set_absorption(float p_absorption);
|
||||
float get_absorption() const;
|
||||
|
||||
void set_particles_path(NodePath p_path);
|
||||
NodePath get_particles_path() const;
|
||||
|
||||
virtual String get_configuration_warning() const;
|
||||
|
||||
ParticleAttractor2D();
|
||||
};
|
||||
|
||||
class Particles2D : public Node2D {
|
||||
|
||||
GDCLASS(Particles2D, Node2D);
|
||||
private:
|
||||
GDCLASS(Particles2D, Node2D)
|
||||
|
||||
public:
|
||||
enum Parameter {
|
||||
PARAM_DIRECTION,
|
||||
PARAM_SPREAD,
|
||||
PARAM_LINEAR_VELOCITY,
|
||||
PARAM_SPIN_VELOCITY,
|
||||
PARAM_ORBIT_VELOCITY,
|
||||
PARAM_GRAVITY_DIRECTION,
|
||||
PARAM_GRAVITY_STRENGTH,
|
||||
PARAM_RADIAL_ACCEL,
|
||||
PARAM_TANGENTIAL_ACCEL,
|
||||
PARAM_DAMPING,
|
||||
PARAM_INITIAL_ANGLE,
|
||||
PARAM_INITIAL_SIZE,
|
||||
PARAM_FINAL_SIZE,
|
||||
PARAM_HUE_VARIATION,
|
||||
PARAM_ANIM_SPEED_SCALE,
|
||||
PARAM_ANIM_INITIAL_POS,
|
||||
PARAM_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_COLOR_PHASES = 4
|
||||
};
|
||||
|
||||
enum ProcessMode {
|
||||
PROCESS_FIXED,
|
||||
PROCESS_IDLE,
|
||||
enum DrawOrder {
|
||||
DRAW_ORDER_INDEX,
|
||||
DRAW_ORDER_LIFETIME,
|
||||
};
|
||||
|
||||
private:
|
||||
float param[PARAM_MAX];
|
||||
float randomness[PARAM_MAX];
|
||||
RID particles;
|
||||
|
||||
struct Particle {
|
||||
bool active;
|
||||
Point2 pos;
|
||||
Vector2 velocity;
|
||||
float rot;
|
||||
float frame;
|
||||
uint64_t seed;
|
||||
Particle() {
|
||||
active = false;
|
||||
seed = 123465789;
|
||||
rot = 0;
|
||||
frame = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Vector<Particle> particles;
|
||||
|
||||
struct AttractorCache {
|
||||
|
||||
Vector2 pos;
|
||||
ParticleAttractor2D *attractor;
|
||||
};
|
||||
|
||||
Vector<AttractorCache> attractor_cache;
|
||||
|
||||
float explosiveness;
|
||||
float preprocess;
|
||||
float lifetime;
|
||||
bool emitting;
|
||||
bool local_space;
|
||||
float emit_timeout;
|
||||
float time_to_live;
|
||||
float time_scale;
|
||||
bool flip_h;
|
||||
bool flip_v;
|
||||
int h_frames;
|
||||
int amount;
|
||||
float lifetime;
|
||||
float pre_process_time;
|
||||
float explosiveness_ratio;
|
||||
float randomness_ratio;
|
||||
float speed_scale;
|
||||
Rect2 visibility_rect;
|
||||
bool local_coords;
|
||||
int fixed_fps;
|
||||
bool fractional_delta;
|
||||
int v_frames;
|
||||
Point2 emissor_offset;
|
||||
Vector2 initial_velocity;
|
||||
Vector2 extents;
|
||||
PoolVector<Vector2> emission_points;
|
||||
int h_frames;
|
||||
|
||||
ProcessMode process_mode;
|
||||
Ref<Material> process_material;
|
||||
|
||||
float time;
|
||||
int active_count;
|
||||
DrawOrder draw_order;
|
||||
|
||||
Ref<Texture> texture;
|
||||
Ref<Texture> normal_map;
|
||||
|
||||
//If no color ramp is set then default color is used. Created as simple alternative to color_ramp.
|
||||
Color default_color;
|
||||
Ref<Gradient> gradient;
|
||||
|
||||
void _process_particles(float p_delta);
|
||||
friend class ParticleAttractor2D;
|
||||
|
||||
Set<ParticleAttractor2D *> attractors;
|
||||
void _update_particle_emission_transform();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
virtual void _validate_property(PropertyInfo &property) const;
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void set_emitting(bool p_emitting);
|
||||
bool is_emitting() const;
|
||||
|
||||
void set_process_mode(ProcessMode p_mode);
|
||||
ProcessMode get_process_mode() const;
|
||||
|
||||
void set_amount(int p_amount);
|
||||
int get_amount() const;
|
||||
|
||||
void set_lifetime(float p_lifetime);
|
||||
void set_pre_process_time(float p_time);
|
||||
void set_explosiveness_ratio(float p_ratio);
|
||||
void set_randomness_ratio(float p_ratio);
|
||||
void set_visibility_rect(const Rect2 &p_aabb);
|
||||
void set_use_local_coordinates(bool p_enable);
|
||||
void set_process_material(const Ref<Material> &p_material);
|
||||
void set_speed_scale(float p_scale);
|
||||
|
||||
bool is_emitting() const;
|
||||
int get_amount() const;
|
||||
float get_lifetime() const;
|
||||
|
||||
void set_time_scale(float p_time_scale);
|
||||
float get_time_scale() const;
|
||||
|
||||
void set_pre_process_time(float p_pre_process_time);
|
||||
float get_pre_process_time() const;
|
||||
float get_explosiveness_ratio() const;
|
||||
float get_randomness_ratio() const;
|
||||
Rect2 get_visibility_rect() const;
|
||||
bool get_use_local_coordinates() const;
|
||||
Ref<Material> get_process_material() const;
|
||||
float get_speed_scale() const;
|
||||
|
||||
void set_emit_timeout(float p_timeout);
|
||||
float get_emit_timeout() const;
|
||||
void set_fixed_fps(int p_count);
|
||||
int get_fixed_fps() const;
|
||||
|
||||
void set_emission_half_extents(const Vector2 &p_extents);
|
||||
Vector2 get_emission_half_extents() const;
|
||||
void set_fractional_delta(bool p_enable);
|
||||
bool get_fractional_delta() const;
|
||||
|
||||
void set_param(Parameter p_param, float p_value);
|
||||
float get_param(Parameter p_param) const;
|
||||
|
||||
void set_randomness(Parameter p_randomness, float p_value);
|
||||
float get_randomness(Parameter p_randomness) const;
|
||||
|
||||
void set_explosiveness(float p_value);
|
||||
float get_explosiveness() const;
|
||||
|
||||
void set_flip_h(bool p_flip);
|
||||
bool is_flipped_h() const;
|
||||
|
||||
void set_flip_v(bool p_flip);
|
||||
bool is_flipped_v() const;
|
||||
|
||||
void set_h_frames(int p_frames);
|
||||
int get_h_frames() const;
|
||||
|
||||
void set_v_frames(int p_frames);
|
||||
int get_v_frames() const;
|
||||
|
||||
void set_color_phases(int p_phases);
|
||||
int get_color_phases() const;
|
||||
|
||||
void set_color_phase_color(int p_phase, const Color &p_color);
|
||||
Color get_color_phase_color(int p_phase) const;
|
||||
|
||||
void set_color_phase_pos(int p_phase, float p_pos);
|
||||
float get_color_phase_pos(int p_phase) const;
|
||||
void set_draw_order(DrawOrder p_order);
|
||||
DrawOrder get_draw_order() const;
|
||||
|
||||
void set_texture(const Ref<Texture> &p_texture);
|
||||
Ref<Texture> get_texture() const;
|
||||
|
||||
void set_color(const Color &p_color);
|
||||
Color get_color() const;
|
||||
void set_normal_map(const Ref<Texture> &p_normal_map);
|
||||
Ref<Texture> get_normal_map() const;
|
||||
|
||||
void set_gradient(const Ref<Gradient> &p_texture);
|
||||
Ref<Gradient> get_gradient() const;
|
||||
virtual String get_configuration_warning() const;
|
||||
|
||||
void set_emissor_offset(const Point2 &p_offset);
|
||||
Point2 get_emissor_offset() const;
|
||||
void set_v_frames(int p_count);
|
||||
int get_v_frames() const;
|
||||
|
||||
void set_use_local_space(bool p_use);
|
||||
bool is_using_local_space() const;
|
||||
|
||||
void set_initial_velocity(const Vector2 &p_velocity);
|
||||
Vector2 get_initial_velocity() const;
|
||||
|
||||
void set_emission_points(const PoolVector<Vector2> &p_points);
|
||||
PoolVector<Vector2> get_emission_points() const;
|
||||
|
||||
void pre_process(float p_delta);
|
||||
void reset();
|
||||
void set_h_frames(int p_count);
|
||||
int get_h_frames() const;
|
||||
|
||||
Rect2 capture_rect() const;
|
||||
Particles2D();
|
||||
~Particles2D();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Particles2D::ProcessMode);
|
||||
VARIANT_ENUM_CAST(Particles2D::Parameter);
|
||||
VARIANT_ENUM_CAST(Particles2D::DrawOrder)
|
||||
|
||||
#endif // PARTICLES_FRAME_H
|
||||
|
|
|
@ -404,6 +404,7 @@ void ParticlesMaterial::init_shaders() {
|
|||
shader_names->emission_texture_point_count = "emission_texture_point_count";
|
||||
shader_names->emission_texture_points = "emission_texture_points";
|
||||
shader_names->emission_texture_normal = "emission_texture_normal";
|
||||
shader_names->emission_texture_color = "emission_texture_color";
|
||||
|
||||
shader_names->trail_divisor = "trail_divisor";
|
||||
shader_names->trail_size_modifier = "trail_size_modifier";
|
||||
|
@ -481,6 +482,28 @@ void ParticlesMaterial::_update_shader() {
|
|||
code += "uniform float anim_speed_random;\n";
|
||||
code += "uniform float anim_offset_random;\n";
|
||||
|
||||
switch (emission_shape) {
|
||||
case EMISSION_SHAPE_POINT: {
|
||||
//do none
|
||||
} break;
|
||||
case EMISSION_SHAPE_SPHERE: {
|
||||
code += "uniform float emission_sphere_radius;\n";
|
||||
} break;
|
||||
case EMISSION_SHAPE_BOX: {
|
||||
code += "uniform vec3 emission_box_extents;\n";
|
||||
} break;
|
||||
case EMISSION_SHAPE_DIRECTED_POINTS: {
|
||||
code += "uniform sampler2D emission_texture_normal : hint_black;\n";
|
||||
} //fallthrough
|
||||
case EMISSION_SHAPE_POINTS: {
|
||||
code += "uniform sampler2D emission_texture_points : hint_black;\n";
|
||||
code += "uniform int emission_texture_point_count;\n";
|
||||
if (emission_color_texture.is_valid()) {
|
||||
code += "uniform sampler2D emission_texture_color : hint_white;\n";
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
code += "uniform vec4 color_value : hint_color;\n";
|
||||
|
||||
code += "uniform int trail_divisor;\n";
|
||||
|
@ -515,25 +538,6 @@ void ParticlesMaterial::_update_shader() {
|
|||
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
|
||||
code += "uniform sampler2D anim_offset_texture;\n";
|
||||
|
||||
switch (emission_shape) {
|
||||
case EMISSION_SHAPE_POINT: {
|
||||
//do none
|
||||
} break;
|
||||
case EMISSION_SHAPE_SPHERE: {
|
||||
code += "uniform float emission_sphere_radius;\n";
|
||||
} break;
|
||||
case EMISSION_SHAPE_BOX: {
|
||||
code += "uniform vec3 emission_box_extents;\n";
|
||||
} break;
|
||||
case EMISSION_SHAPE_DIRECTED_POINTS: {
|
||||
code += "uniform sampler2D emission_texture_normal : hint_black;\n";
|
||||
} //fallthrough
|
||||
case EMISSION_SHAPE_POINTS: {
|
||||
code += "uniform sampler2D emission_texture_points : hint_black;\n";
|
||||
code += "uniform int emission_texture_point_count;\n";
|
||||
} break;
|
||||
}
|
||||
|
||||
if (trail_size_modifier.is_valid()) {
|
||||
code += "uniform sampler2D trail_size_modifier;\n";
|
||||
}
|
||||
|
@ -576,6 +580,11 @@ void ParticlesMaterial::_update_shader() {
|
|||
code += "\n";
|
||||
code += "\n";
|
||||
code += "\n";
|
||||
if (emission_shape >= EMISSION_SHAPE_POINTS) {
|
||||
code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
|
||||
code += " ivec2 emission_tex_size = textureSize( emission_texture_points, 0 );\n";
|
||||
code += " ivec2 emission_tex_ofs = ivec2( point % emission_tex_size.x, point / emission_tex_size.x );\n";
|
||||
}
|
||||
code += " if (RESTART) {\n";
|
||||
|
||||
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
|
||||
|
@ -593,11 +602,21 @@ void ParticlesMaterial::_update_shader() {
|
|||
else
|
||||
code += " float tex_anim_offset = 0.0;\n";
|
||||
|
||||
code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
|
||||
code += " float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n";
|
||||
code += " vec3 rot_xz=vec3( sin(angle1), 0.0, cos(angle1) );\n";
|
||||
code += " vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n";
|
||||
code += " VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
|
||||
code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
|
||||
code += " vec3 rot=vec3( cos(angle1), sin(angle1),0.0 );\n";
|
||||
code += " VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
|
||||
|
||||
} else {
|
||||
//initiate velocity spread in 3D
|
||||
code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
|
||||
code += " float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n";
|
||||
code += " vec3 rot_xz=vec3( sin(angle1), 0.0, cos(angle1) );\n";
|
||||
code += " vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n";
|
||||
code += " VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
|
||||
}
|
||||
|
||||
code += " float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
|
||||
code += " CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
|
||||
code += " CUSTOM.y=0.0;\n"; //phase
|
||||
|
@ -614,21 +633,31 @@ void ParticlesMaterial::_update_shader() {
|
|||
} break;
|
||||
case EMISSION_SHAPE_POINTS:
|
||||
case EMISSION_SHAPE_DIRECTED_POINTS: {
|
||||
code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
|
||||
code += " ivec2 tex_size = textureSize( emission_texture_points, 0 );\n";
|
||||
code += " ivec2 tex_ofs = ivec2( point % tex_size.x, point / tex_size.x );\n";
|
||||
code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, tex_ofs,0).xyz;\n";
|
||||
code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs,0).xyz;\n";
|
||||
|
||||
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
|
||||
code += " vec3 normal = texelFetch(emission_texture_normal, tex_ofs,0).xyz;\n";
|
||||
code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n";
|
||||
code += " vec3 tangent = normalize(cross(v0, normal));\n";
|
||||
code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
|
||||
code += " VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n";
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
|
||||
code += " mat2 rotm;";
|
||||
code += " rotm[0]=texelFetch(emission_texture_normal, emission_tex_ofs,0).xy;\n";
|
||||
code += " rotm[1]=rotm[0].yx * vec2(1.0,-1.0);\n";
|
||||
code += " VELOCITY.xy = rotm * VELOCITY.xy;\n";
|
||||
} else {
|
||||
code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs,0).xyz;\n";
|
||||
code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n";
|
||||
code += " vec3 tangent = normalize(cross(v0, normal));\n";
|
||||
code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
|
||||
code += " VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n";
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n";
|
||||
code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
code += " VELOCITY.z=0.0;\n";
|
||||
code += " TRANSFORM[3].z=0.0;\n";
|
||||
}
|
||||
|
||||
code += " } else {\n";
|
||||
|
||||
|
@ -685,6 +714,9 @@ void ParticlesMaterial::_update_shader() {
|
|||
|
||||
code += " vec3 force = gravity; \n";
|
||||
code += " vec3 pos = TRANSFORM[3].xyz; \n";
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
code += " pos.z=0.0; \n";
|
||||
}
|
||||
code += " //apply linear acceleration\n";
|
||||
code += " force+=normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random);\n";
|
||||
code += " //apply radial acceleration\n";
|
||||
|
@ -693,11 +725,17 @@ void ParticlesMaterial::_update_shader() {
|
|||
code += " //org=p_transform.origin;\n";
|
||||
code += " force+=normalize(pos-org) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random);\n";
|
||||
code += " //apply tangential acceleration;\n";
|
||||
code += " force+=normalize(cross(normalize(pos-org),normalize(gravity))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n";
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
code += " force+=vec3(normalize((pos-org).yx * vec2(-1.0,1.0)),0.0) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n";
|
||||
|
||||
} else {
|
||||
code += " force+=normalize(cross(normalize(pos-org),normalize(gravity))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n";
|
||||
}
|
||||
code += " //apply attractor forces\n";
|
||||
code += " VELOCITY+=force * DELTA;\n";
|
||||
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
|
||||
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
|
||||
code += " VELOCITY=normalize(VELOCITY)*tex_linear_velocity;\n";
|
||||
}
|
||||
code += " if (damping+tex_damping>0.0) {\n";
|
||||
code += " \n";
|
||||
code += " float v = length(VELOCITY);\n";
|
||||
|
@ -709,9 +747,16 @@ void ParticlesMaterial::_update_shader() {
|
|||
code += " VELOCITY=normalize(VELOCITY) * v;\n";
|
||||
code += " }\n";
|
||||
code += " }\n";
|
||||
code += " float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random)*3.1416/180.0;\n";
|
||||
code += " CUSTOM.x=((base_angle+tex_angle)+CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random))*3.1416/180.0;\n"; //angle
|
||||
code += " CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*LIFETIME*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
|
||||
code += " float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
|
||||
code += " base_angle+=CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n";
|
||||
code += " CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
|
||||
code += " CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
|
||||
if (flags[FLAG_ANIM_LOOP]) {
|
||||
code += " CUSTOM.z=mod(CUSTOM.z,1.0);\n"; //loop
|
||||
|
||||
} else {
|
||||
code += " CUSTOM.z=clamp(CUSTOM.z,0.0,1.0);\n"; //0 to 1 only
|
||||
}
|
||||
code += " }\n";
|
||||
//apply color
|
||||
//apply hue rotation
|
||||
|
@ -747,28 +792,40 @@ void ParticlesMaterial::_update_shader() {
|
|||
} else {
|
||||
code += " COLOR = color_value * hue_rot_mat;\n";
|
||||
}
|
||||
if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) {
|
||||
code += " COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n";
|
||||
}
|
||||
if (trail_color_modifier.is_valid()) {
|
||||
code += "if (trail_divisor>1) { COLOR*=textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n";
|
||||
}
|
||||
code += "\n";
|
||||
//orient particle Y towards velocity
|
||||
if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
|
||||
code += " if (length(VELOCITY)>0.0) {TRANSFORM[1].xyz=normalize(VELOCITY);} else {TRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);}\n";
|
||||
code += " if (TRANSFORM[1].xyz==normalize(TRANSFORM[0].xyz)) {\n";
|
||||
code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
|
||||
code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
|
||||
code += " } else {\n";
|
||||
code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
|
||||
code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
|
||||
code += " }\n";
|
||||
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
|
||||
code += " TRANSFORM[0]=vec4(cos(CUSTOM.x),-sin(CUSTOM.x),0.0,0.0);\n";
|
||||
code += " TRANSFORM[1]=vec4(sin(CUSTOM.x),cos(CUSTOM.x),0.0,0.0);\n";
|
||||
code += " TRANSFORM[2]=vec4(0.0,0.0,1.0,0.0);\n";
|
||||
|
||||
} else {
|
||||
code += "\tTRANSFORM[0].xyz=normalize(TRANSFORM[0].xyz);\n";
|
||||
code += "\tTRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);\n";
|
||||
code += "\tTRANSFORM[2].xyz=normalize(TRANSFORM[2].xyz);\n";
|
||||
}
|
||||
//turn particle by rotation in Y
|
||||
if (flags[FLAG_ROTATE_Y]) {
|
||||
code += "\tTRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n";
|
||||
//orient particle Y towards velocity
|
||||
if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
|
||||
code += " if (length(VELOCITY)>0.0) {TRANSFORM[1].xyz=normalize(VELOCITY);} else {TRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);}\n";
|
||||
code += " if (TRANSFORM[1].xyz==normalize(TRANSFORM[0].xyz)) {\n";
|
||||
code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
|
||||
code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
|
||||
code += " } else {\n";
|
||||
code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
|
||||
code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
|
||||
code += " }\n";
|
||||
} else {
|
||||
code += "\tTRANSFORM[0].xyz=normalize(TRANSFORM[0].xyz);\n";
|
||||
code += "\tTRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);\n";
|
||||
code += "\tTRANSFORM[2].xyz=normalize(TRANSFORM[2].xyz);\n";
|
||||
}
|
||||
//turn particle by rotation in Y
|
||||
if (flags[FLAG_ROTATE_Y]) {
|
||||
code += "\tTRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n";
|
||||
}
|
||||
}
|
||||
//scale by scale
|
||||
code += " float base_scale=mix(scale*tex_scale,1.0,scale_random*scale_rand);\n";
|
||||
|
@ -779,6 +836,10 @@ void ParticlesMaterial::_update_shader() {
|
|||
code += " TRANSFORM[0].xyz*=base_scale;\n";
|
||||
code += " TRANSFORM[1].xyz*=base_scale;\n";
|
||||
code += " TRANSFORM[2].xyz*=base_scale;\n";
|
||||
if (flags[FLAG_DISABLE_Z]) {
|
||||
code += " VELOCITY.z=0.0;\n";
|
||||
code += " TRANSFORM[3].z=0.0;\n";
|
||||
}
|
||||
code += "}\n";
|
||||
code += "\n";
|
||||
|
||||
|
@ -1130,6 +1191,16 @@ void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normal
|
|||
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture);
|
||||
}
|
||||
|
||||
void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) {
|
||||
|
||||
emission_color_texture = p_colors;
|
||||
RID texture;
|
||||
if (p_colors.is_valid())
|
||||
texture = p_colors->get_rid();
|
||||
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture);
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
||||
void ParticlesMaterial::set_emission_point_count(int p_count) {
|
||||
|
||||
emission_point_count = p_count;
|
||||
|
@ -1158,6 +1229,11 @@ Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const {
|
|||
return emission_normal_texture;
|
||||
}
|
||||
|
||||
Ref<Texture> ParticlesMaterial::get_emission_color_texture() const {
|
||||
|
||||
return emission_color_texture;
|
||||
}
|
||||
|
||||
int ParticlesMaterial::get_emission_point_count() const {
|
||||
|
||||
return emission_point_count;
|
||||
|
@ -1247,7 +1323,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
|
|||
property.usage = 0;
|
||||
}
|
||||
|
||||
if (property.name == "emission_point_texture" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
|
||||
if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
|
||||
property.usage = 0;
|
||||
}
|
||||
|
||||
|
@ -1301,6 +1377,9 @@ void ParticlesMaterial::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture:Texture"), &ParticlesMaterial::set_emission_normal_texture);
|
||||
ClassDB::bind_method(D_METHOD("get_emission_normal_texture:Texture"), &ParticlesMaterial::get_emission_normal_texture);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture:Texture"), &ParticlesMaterial::set_emission_color_texture);
|
||||
ClassDB::bind_method(D_METHOD("get_emission_color_texture:Texture"), &ParticlesMaterial::get_emission_color_texture);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count);
|
||||
ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count);
|
||||
|
||||
|
@ -1326,10 +1405,12 @@ void ParticlesMaterial::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_color_texture", "get_emission_color_texture");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count");
|
||||
ADD_GROUP("Flags", "flag_");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z);
|
||||
ADD_GROUP("Spread", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
|
||||
|
@ -1379,12 +1460,13 @@ void ParticlesMaterial::_bind_methods() {
|
|||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
|
||||
ADD_GROUP("Animation", "anim_");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP);
|
||||
|
||||
BIND_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
|
||||
BIND_CONSTANT(PARAM_ANGULAR_VELOCITY);
|
||||
|
|
|
@ -154,6 +154,8 @@ public:
|
|||
enum Flags {
|
||||
FLAG_ALIGN_Y_TO_VELOCITY,
|
||||
FLAG_ROTATE_Y,
|
||||
FLAG_DISABLE_Z,
|
||||
FLAG_ANIM_LOOP,
|
||||
FLAG_MAX
|
||||
};
|
||||
|
||||
|
@ -171,11 +173,12 @@ private:
|
|||
struct {
|
||||
uint32_t texture_mask : 16;
|
||||
uint32_t texture_color : 1;
|
||||
uint32_t flags : 2;
|
||||
uint32_t flags : 4;
|
||||
uint32_t emission_shape : 2;
|
||||
uint32_t trail_size_texture : 1;
|
||||
uint32_t trail_color_texture : 1;
|
||||
uint32_t invalid_key : 1;
|
||||
uint32_t has_emission_color : 1;
|
||||
};
|
||||
|
||||
uint32_t key;
|
||||
|
@ -213,6 +216,7 @@ private:
|
|||
mk.emission_shape = emission_shape;
|
||||
mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0;
|
||||
mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0;
|
||||
mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
|
||||
|
||||
return mk;
|
||||
}
|
||||
|
@ -269,6 +273,7 @@ private:
|
|||
StringName emission_texture_point_count;
|
||||
StringName emission_texture_points;
|
||||
StringName emission_texture_normal;
|
||||
StringName emission_texture_color;
|
||||
|
||||
StringName trail_divisor;
|
||||
StringName trail_size_modifier;
|
||||
|
@ -302,8 +307,11 @@ private:
|
|||
Vector3 emission_box_extents;
|
||||
Ref<Texture> emission_point_texture;
|
||||
Ref<Texture> emission_normal_texture;
|
||||
Ref<Texture> emission_color_texture;
|
||||
int emission_point_count;
|
||||
|
||||
bool anim_loop;
|
||||
|
||||
int trail_divisor;
|
||||
|
||||
Ref<CurveTexture> trail_size_modifier;
|
||||
|
@ -347,6 +355,7 @@ public:
|
|||
void set_emission_box_extents(Vector3 p_extents);
|
||||
void set_emission_point_texture(const Ref<Texture> &p_points);
|
||||
void set_emission_normal_texture(const Ref<Texture> &p_normals);
|
||||
void set_emission_color_texture(const Ref<Texture> &p_colors);
|
||||
void set_emission_point_count(int p_count);
|
||||
|
||||
EmissionShape get_emission_shape() const;
|
||||
|
@ -354,6 +363,7 @@ public:
|
|||
Vector3 get_emission_box_extents() const;
|
||||
Ref<Texture> get_emission_point_texture() const;
|
||||
Ref<Texture> get_emission_normal_texture() const;
|
||||
Ref<Texture> get_emission_color_texture() const;
|
||||
int get_emission_point_count() const;
|
||||
|
||||
void set_trail_divisor(int p_divisor);
|
||||
|
|
|
@ -471,7 +471,7 @@ void register_scene_types() {
|
|||
ClassDB::register_virtual_class<CanvasItem>();
|
||||
ClassDB::register_class<Node2D>();
|
||||
ClassDB::register_class<Particles2D>();
|
||||
ClassDB::register_class<ParticleAttractor2D>();
|
||||
//ClassDB::register_class<ParticleAttractor2D>();
|
||||
ClassDB::register_class<Sprite>();
|
||||
//ClassDB::register_type<ViewportSprite>();
|
||||
ClassDB::register_class<SpriteFrames>();
|
||||
|
|
|
@ -612,6 +612,7 @@ public:
|
|||
TYPE_POLYGON,
|
||||
TYPE_MESH,
|
||||
TYPE_MULTIMESH,
|
||||
TYPE_PARTICLES,
|
||||
TYPE_CIRCLE,
|
||||
TYPE_TRANSFORM,
|
||||
TYPE_CLIP_IGNORE,
|
||||
|
@ -707,6 +708,16 @@ public:
|
|||
CommandMultiMesh() { type = TYPE_MULTIMESH; }
|
||||
};
|
||||
|
||||
struct CommandParticles : public Command {
|
||||
|
||||
RID particles;
|
||||
RID texture;
|
||||
RID normal_map;
|
||||
int h_frames;
|
||||
int v_frames;
|
||||
CommandParticles() { type = TYPE_PARTICLES; }
|
||||
};
|
||||
|
||||
struct CommandCircle : public Command {
|
||||
|
||||
Point2 pos;
|
||||
|
@ -844,6 +855,15 @@ public:
|
|||
|
||||
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||
|
||||
} break;
|
||||
case Item::Command::TYPE_PARTICLES: {
|
||||
|
||||
const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
|
||||
if (particles_cmd->particles.is_valid()) {
|
||||
Rect3 aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles);
|
||||
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||
}
|
||||
|
||||
} break;
|
||||
case Item::Command::TYPE_CIRCLE: {
|
||||
|
||||
|
|
|
@ -637,6 +637,25 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID
|
|||
|
||||
canvas_item->commands.push_back(m);
|
||||
}
|
||||
void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames) {
|
||||
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
|
||||
Item::CommandParticles *part = memnew(Item::CommandParticles);
|
||||
ERR_FAIL_COND(!part);
|
||||
part->particles = p_particles;
|
||||
part->texture = p_texture;
|
||||
part->normal_map = p_normal;
|
||||
part->h_frames = p_h_frames;
|
||||
part->v_frames = p_v_frames;
|
||||
|
||||
//take the chance and request processing for them, at least once until they become visible again
|
||||
VSG::storage->particles_request_process(p_particles);
|
||||
|
||||
canvas_item->commands.push_back(part);
|
||||
}
|
||||
|
||||
void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton) {
|
||||
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
|
|
|
@ -173,6 +173,7 @@ public:
|
|||
void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID());
|
||||
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_skeleton = RID());
|
||||
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton = RID());
|
||||
void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames);
|
||||
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
|
||||
void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
|
||||
void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);
|
||||
|
|
|
@ -877,7 +877,8 @@ public:
|
|||
BIND2(particles_set_draw_passes, RID, int)
|
||||
BIND3(particles_set_draw_pass_mesh, RID, int, RID)
|
||||
|
||||
BIND1R(Rect3, particles_get_current_aabb, RID);
|
||||
BIND1R(Rect3, particles_get_current_aabb, RID)
|
||||
BIND2(particles_set_emission_transform, RID, const Transform &)
|
||||
|
||||
#undef BINDBASE
|
||||
//from now on, calls forwarded to this singleton
|
||||
|
@ -1049,6 +1050,7 @@ public:
|
|||
BIND8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID)
|
||||
BIND3(canvas_item_add_mesh, RID, const RID &, RID)
|
||||
BIND3(canvas_item_add_multimesh, RID, RID, RID)
|
||||
BIND6(canvas_item_add_particles, RID, RID, RID, RID, int, int)
|
||||
BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
|
||||
BIND2(canvas_item_add_clip_ignore, RID, bool)
|
||||
BIND2(canvas_item_set_sort_children_by_y, RID, bool)
|
||||
|
|
|
@ -320,6 +320,7 @@ public:
|
|||
|
||||
FUNC2(particles_set_draw_passes, RID, int)
|
||||
FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
|
||||
FUNC2(particles_set_emission_transform, RID, const Transform &)
|
||||
|
||||
FUNC1R(Rect3, particles_get_current_aabb, RID)
|
||||
|
||||
|
@ -476,6 +477,7 @@ public:
|
|||
FUNC8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID)
|
||||
FUNC3(canvas_item_add_mesh, RID, const RID &, RID)
|
||||
FUNC3(canvas_item_add_multimesh, RID, RID, RID)
|
||||
FUNC6(canvas_item_add_particles, RID, RID, RID, RID, int, int)
|
||||
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
|
||||
FUNC2(canvas_item_add_clip_ignore, RID, bool)
|
||||
FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
|
||||
|
|
|
@ -501,6 +501,8 @@ public:
|
|||
|
||||
virtual Rect3 particles_get_current_aabb(RID p_particles) = 0;
|
||||
|
||||
virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; //this is only used for 2D, in 3D it's automatic
|
||||
|
||||
/* CAMERA API */
|
||||
|
||||
virtual RID camera_create() = 0;
|
||||
|
@ -793,6 +795,7 @@ public:
|
|||
virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0;
|
||||
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_skeleton = RID()) = 0;
|
||||
virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton = RID()) = 0;
|
||||
virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, int p_h_frames, int p_v_frames) = 0;
|
||||
virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
|
||||
virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0;
|
||||
virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0;
|
||||
|
|
Loading…
Reference in New Issue